Alterando arquivos de configuração

Caso sejam executados pelo root, os scripts podem também alterar arquivos de configuração do sistema, modificando entradas existentes ou incluindo novas configurações. O comando mais usado para fazer substituições é o sed. Para simplesmente adicionar linhas no final do arquivo, você pode usar o echo, o mesmo comando que usamos para escrever mensagens na tela.

Por exemplo, um erro comum ao acessar partições do Windows formatadas em NTFS é a partição ser montada com permissão de leitura apenas para o root. Você só consegue ver os arquivos abrindo o gerenciador de arquivos como root, o que é desconfortável.

Isto acontece porque o default do mount é montar partições NTFS e FAT com permissão de acesso apenas para o root. Para que outros usuários possam visualizar os arquivos, é necessário montar incluindo a opção “umask=000“.

A tarefa é relativamente simples, basta abrir o arquivo “/etc/fstab” e adicionar a opção na linha referente à partição.

Ao invés de:

/dev/hda1 /mnt/hda1 auto noauto,users,exec 0 0

Ficaríamos com:

/dev/hda1 /mnt/hda1 auto noauto,users,exec,umask=000 0 0

Até aí tudo bem. O problema é que este parâmetro pode ser usado apenas em partições FAT ou NTFS. Se você usar em partições formatadas em ReiserFS ou EXT, elas não montam.

Ou seja, ao fazer isso via script, precisamos primeiro ter certeza de que a partição está formatada em NTFS, antes de alterar o “/etc/fstab”.

Uma forma de fazer isto é verificando a saída do comando “fdisk -l“, que mostra detalhes sobre as partições, como em:

# fdisk -l /dev/hda
Disk /dev/hda: 20.0 GB, 20003880960 bytes
255 heads, 63 sectors/track, 2432 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot    Start       End         Blocks           Id        System

/dev/hda1 *    1           401         3221001          7         HPFS/NTFS
/dev/hda2      402         1042        5148832+         83        Linux
/dev/hda3      1116        2432        10578802+        5         Extended
/dev/hda4      1043        1115        586372+          83        Linux
/dev/hda5      1116        1164        393561           82        Linux swap / Solaris
/dev/hda6      1165        2432        10185178+        83        Linux

Podemos então usar o grep para filtrar a saída e carregar o resultado dentro de uma variável, de modo que ela contenha alguma coisa apenas se a partição testada estiver formatada em NTFS, como em:

winntfs=`fdisk -l /dev/hda | grep hda1 | grep NTFS`

Note que aqui estamos usando três comandos diferentes, ligados por pipes. Esta é uma prática comum na hora de filtrar a saída de comandos, já que é difícil chegar a um único comando que faça de uma vez tudo o que você precisa. Neste exemplo, o “grep hda1” vai remover todas as linhas, deixando apenas a linha referente à partição “/dev/hda1”. O “grep NTFS” verifica a linha e deixa-a passar apenas se a partição estiver formatada em NTFS, visto que, caso ela esteja formatada em outro sistema, a string com a identificação do sistema de arquivos será outra.

Usamos em seguida uma função que verifica se a variável é não nula (-n). Por causa dos dois comandos do grep, ela só conterá algum texto se o /dev/hda1 estiver formatado em NTFS. Usamos então um if com o comando do sed para alterar a linha no “/etc/fstab” caso positivo:

if [ -n "$winntfs" ]; then

    # O gigantesco comando abaixo forma uma única linha:
    sed -e 's/\/dev\/hda1 \/mnt\/hda1 auto noauto,users,exec 0 0/\/dev\/hda1 \/mnt\/hda1 
auto noauto,users,exec,umask=000 0 0/g' /etc/fstab > /tmp/fstab2

    rm -f /etc/fstab; mv /etc/fstab2 /etc/fstab
fi

Veja que a linha do sed é um pouco longa. A sintaxe básica para fazer substituições é:

$ sed -e ‘s/texto/novo-texto/g’ arquivo > novo-arquivo

Ele sempre gera um novo arquivo com as alterações, por isso depois do comando você ainda precisa remover o arquivo original e renomear o novo arquivo. Caso dentro da string de texto a substituir existam barras ou caracteres especiais, use barras invertidas (\) como no exemplo, para demarcá-los. As barras invertidas indicam que o caractere seguinte não deve ser interpretado.

O comando “sed -e ‘s/texto/novo-texto/g’ arquivo > novo-arquivo” que vimos, simplesmente substitui todas as instâncias da palavra “texto” por “novo-texto”. Você precisa certificar-se que a palavra só existe dentro do contexto que imagina, caso contrário, o comando pode facilmente causar acidentes. O ideal é que você seja sempre o mais específico possível.

Para deletar uma linha, use o comando “sed -e ‘/texto/D’ arquivo > novo-arquivo, como em:

$ sed -e ‘/Load “dri”/D’ /etc/X11/xorg.conf > /tmp/xorg.conf.new

O sed suporta também alguns caracteres especiais. O “^”, por exemplo, indica o início da linha. Para remover todas as linhas que começam com “#” (ou seja, linhas com comentários), use:

$ sed -e ‘/^\#/D’ /etc/lilo.conf > /tmp/lilo.conf.new

Note que precisei incluir uma barra invertida antes do “#”. Para remover todas as linhas em branco de um arquivo, use:

$ sed -e ‘/^$/D’ /etc/X11/xorg.conf > /tmp/xorg.conf.new

É possível também combinar vários comandos do sed usando o pipe, fazendo com que a saída de um passe também pelo outro antes de ser escrita no arquivo final. Para remover todas as linhas com comentários e todas as em branco, o comando seria:

$ sed -e ‘/^\#/D’ /etc/lilo.conf | sed -e ‘/^$/D’ /etc/lilo.conf > /tmp/lilo.conf.new

Para eliminar espaços repetidos num arquivo (útil caso você queira filtrar alguma informação usando o cut):

$ sed -r ‘s/ +/ /g’ /etc/X11/xorg.conf > /tmp/xorg.conf.new

Para substituir todos os espaços por quebras de linha (representadas pelo “\n” dentro do sed):

$ sed -e ‘s/ /\n/g’ /tmp/myfreq >> /tmp/myfreq2

Para remover todas as quebras de linhas de um arquivo, fazendo com que tudo fique numa única linha (o que pode ser útil para facilitar a localização de determinadas informações, que originalmente estavam em várias linhas separadas), use esta função inventada pelo Thobias Salazar:

$ sed ‘:a;$!N;s/\n//;ta;’ ~/.synergy.conf > /tmp/synergy.conf

Você pode usá-la junto com a função sed ‘s/^/ /’, que adiciona um caracter no início de cada linha. Ao usar esta função (‘s/^/ /’), você pode substituir o espaço entre a segunda e terceira barra por outro caracter, ou conjunto de caracteres, como em sed ‘s/^/\&\&/’. Veja um exemplo de uso dos dois combinados, que formata o arquivo “.synergy.conf” (usado pelo Synergy, que vimos no capítulo 2):

$ cat .synergy.conf | sed ‘s/^/ /’ | sed ‘:a;$!N;s/\n//;ta;’

section: screens kurumin: semprao: end section: links semprao: right = kurumin kurumin: left = semprao end section: aliases kurumin: 192.168.1.102 end

O sed, aliado ao grep, pode ser usado também para criar scripts inteligentes, que verificam a configuração do sistema e, se necessário alteram as linhas necessárias.

Por exemplo, para instalar o FreeNX server no Debian, seguindo o tutorial que publiquei no Guia do Hardware (https://www.hardware.com.br/tutoriais/usando-freenx-server-atualizado/), é necessário adicionar uma linha no “/etc/apt/sources.list”, com o repositório do Kanotix que possui os pacotes. Estes pacotes possuem algumas dependências do Unstable, de forma que o sources.list precisa conter também a linha correspondente.

Este é o trecho do script do ícone mágico que escrevi para o Kurumin, que verifica e altera o arquivo caso necessário:

# Verifica se o sources.list contém entradas para o unstable,
# se não tiver adiciona:

unstable=`sed '/^$/d' /etc/apt/sources.list | sed '/#/d' \
| grep "unstable main contrib"`

if [ -z "$unstable" ]; then
    echo "deb https://ftp.us.debian.org/debian unstable \
    main contrib non-free" >> /etc/apt/sources.list
    remover="1"
fi

# Adiciona o repositório do freenx
kano=`sed '/^$/d' /etc/apt/sources.list \
| sed '/#/d' | grep "project/kanotix/unstable/"`

if [ -z "$kano" ]; then
    echo 'deb https://debian.tu-bs.de/project/kanotix/unstable\
    / ./' >> /etc/apt/sources.list
    removerkano="1"
fi

# Instala o freenx a partir do unstable do Kano
apt-get update
apt-get install -t unstable freenx
nxsetup --install --setup-nomachine-key

# Remove o unstable e/ou o repositorio do kano, se adicionado:
if [ "$remover" = "1" ]; then
    rm -f /tmp/sources.list
    sed -e '/deb http:\/\/ftp.us.debian.org\/debian unstable main contrib non-free/D' \
    /etc/apt/sources.list > /tmp/sources.list
    rm -f /etc/apt/sources.list
    cp /tmp/sources.list /etc/apt/sources.list
    apt-get update
fi

if [ "$removerkano" = "1" ]; then
    rm -f /tmp/sources.list
    sed -e '/deb http:\/\/debian.tu-bs.de\/project\/kanotix\/unstable\/ \.\//D' \
    /etc/apt/sources.list > /tmp/sources.list
    rm -f /etc/apt/sources.list
    cp /tmp/sources.list /etc/apt/sources.list
    apt-get update
fi

Logo no início do script são definidas duas variáveis, “unstable” e “kano” que são usadas para verificar se as linhas dos repositórios de que o script precisa estão ou não disponíveis no script. Esta informação é usada para decidir se se elas devem ser adicionadas ou não.

Localizar linhas no arquivo pode ser um pouco complexo. Como explicar para o script que ele deve ignorar a linha caso esteja comentada e como fazer ele ignorar pequenas variações nas linhas (como os códigos de país nas linhas dos repositórios do Debian)?

Prevendo isso, estou usando um “super pipe”, que usa dois comandos do sed para remover as linhas em branco (sed ‘/^$/d’), as linhas comentadas (sed ‘/#/d’) e em seguida o grep para filtrar apenas a linha que estou procurando. Para tornar o script mais flexível, faço a busca por apenas parte da linha, isso evita que a função deixe passar uma entrada similar, mas com outro mirror:

unstable=`sed ‘/^$/d’ /etc/apt/sources.list | sed ‘/#/d’ \
| grep “unstable main contrib”`

Caso as variáveis estejam vazias (-z), significa que as linhas não existem no arquivo. Neste caso, entram em ação as funções que coloco em seguida, que adicionam as linhas necessárias e criam mais duas variáveis (“remover” e “removerkano”) que são usadas para que o script “lembre” que fez as alterações e remova as linhas no final, deixando o arquivo da forma como estava originalmente.

A função para remover as linhas usa novamente o sed, desta vez numa sintaxe mais simples, que simplesmente deleta as linhas (sed -e ‘/texto/D’) anteriormente adicionadas. O sed não é capaz de salvar as alterações diretamente no arquivo, por isso é sempre necessário salvar num arquivo temporário e depois substituir o arquivo original por ele.

Você pode ver mais dicas e exemplos do uso do sed na página do Aurélio: https://aurelio.net/sed/.

Ver Mais

Esta postagem foi modificada pela última vez em 25/09/2010 15:53

Postagem relacionada