************************** ************************** Global Replace --------------------------------------------------------------------- Este shell script pode vir a ser util. O que ele faz e simplesmente trocar todas as ocorrencias de determinado string por uma outra em uma numero de arquivos especificados na linha de comando, aceitando inclusive wildcards. Por exemplo, o comando % repl rubens joao * substituiria todas as ocorrencias de "rubens" por "joao" em todos os arquivos do diretorio corrente. Alem disto, este shell script aborda alguns pontos interessantes com relacao a programacao shell. O codigo da shell foi comentado para esclarecer as tecnicas de programacao. #! /bin/sh # Teste para verificar se todos os argumentos foram passados # na linha de comando (minimo de 3, duas strings (de, para) e # nome(s) do(s) arquivo(s). Se nao, sai e envia mensagem de erro if [ $# -lt 3 ] then echo "Uso $0: DE-argumento PARA-argumento arquivos" >&2 exit 1 fi # atribui a variavel DE o valor da string a ser substituida # e desloca as variaveis ($3 passa a ser $2, $2 passa a ser $1) # O deslocamento das variaveis e feito com o comando shift DE=$1; shift # atribui a variavel PARA o valor final da string # $1 agora e o argumento de numero 2, string destino. PARA=$1; shift # Na entrada do laco, $1 representa o nome do primeiro arquivo # onde serao efetuadas as alteracoes until [ $# -eq 0 ] # Continua no laco ate que o numero de argumentos seja igual a zero # ou seja, ate que nao existam mais arquivos a serem processados. do # Testa a existencia do arquivo if [ ! -r $1 ] then echo "no file $1" >& 2;shift # A modificacao nos arquivos e feita com o comando sed, que redireciona # a saida para um arquivo temporario, que ira possuir o nome do shell ($0) # seguido do numero de identificacao do processo ($$) else sed -e "s/$DE/$PARA/g" $1 > /tmp/$0$$ mv /tmp/$0$$ $1; echo "alteracoes efetuadas em $1" >&2 shift fi ********************************************************************************************** Criacao de Scripts com o bit de execucao ligado --------------------------------------------------------------------- Muitas vezes criamos shell scripts com o programa vi. Todavia o modo de execucao destes arquivos normalmente (dependendo do valor que voce definiu para o umask) e 644, ou seja, voce nao consegue executar este arquivo. Um script bastante simples que resolve este pequeno incomodo e o script xvi (eXecutable vi). Ele usa o vi normalmente para se editar o arquivo, porem, apos o fim da edicao, seta o modo de execucao do script. Agora, o script: -------------------------------------------------------------------------xvi #!/bin/sh # # Autor: Queiroz # Data : 11/08/94 # # Este shell script permite a edicao de arquivos executaveis # alterando as permissoes default para o modo 755 # if [ $# -eq 0 ]; then echo 1>&2 Sintaxe: $0 arquivo[s] exit 1 fi for file do vi $file chmod 755 $file done ... Bastante simples, nao? ---------------------------------------------- ********************************************************************************************** Gerenciamento de Espaco em Disco --------------------------------------------------------------------- A tarefa de manter espaco em disco em quantidade suficiente para que os usuarios consigam trabalhar e o sistema operacional consiga funcionar decentemente e uma das mais importantes do administrador de sistemas. O comando "find" e uma ferramenta excelente para desempenhar este tipo de tarefa. Existem arquivos que aparecem no sistema de tempos em tempos e que ocupam um espaco consideravel e nao servem para nada. Arquivos chamados "core" por exemplo sao resultados de um dump de memoria realizado por um programa para que o programador determine o que ocorreu de errado. Normalmente a maioria das pessoas nao se dao ao trabalho de remover estes arquivos e eles continuam a existir no seu disco por um longo tempo, apenas ocupando espaco. Arquivos postscript tambem ocupam muito espaco. Nao recomendo que se remova estes arquivos, mas pelo menos eles podem ser compactados. Arquivos ha mais de um dia sem serem modificados e residentes no diretorio /tmp, tambem nao devem continuar vivendo. Alguns administradores tambem tem por habito remover os arquivos chamados a.out (embora isto possa gerar atritos com alguns usuarios). Tambem pode ser interessante descobrir quem esta abrigando arquivos realmente grandes em seus diretorios para se tomar providencias. Bem, a descoberta de todos estes arquivos e as acoes apropriadas podem ser tomadas automaticamente atraves de um simples shell script: --------------------------------------------------------------------- #! /bin/sh # Encontra e apaga arquivos chamados core find / -name core -print | xargs rm # Encontra e compacta arquivos postscript find / -name \*.ps -print | xargs gzip # Encontra e remove arquivos chamados a.out find / -name a.out -print | xargs rm # Descobre arquivos maiores que 2048 blocos de 512 bytes e envia a relacao # para o administrador de sistemas find / -size +2048 -print | xargs ls -l | mail root # Apaga arquivos residentes no diretorio /tmp que nao tenham sido # modificados ha mais de um dia find /tmp -mtime +1 -print | xargs rm ------------------------------------------------------------ ********************************************************************************************** Verificacao dos argumentos em shell scripts --------------------------------------------------------------------- E fundamental que todo shell script verifique, antes de realizar qualquer acao, que o numero correto de argumentos foi fornecido por quem invoca o programa: #!/bin/sh if [ $# -ne 3 ]; then echo 1>&2 Sintaxe: $0 a b c exit 999 fi O script acima requer tres argumentos que, se nao forem fornecidos, impedem a execucao do programa e seta o codigo de retorno com o valor 999. Normalmente um codigo de retorno diferente de zero indica a ocorrencia de um erro. Outro exemplo, o programa tiraacento, ja veiculado nesta lista: #! /bin/sh MACROS=/home/queiroz/bin infile=$1 outfile=$2 # Neste ponto verifica-se se o numero de argumentos fornecido # foi igual a dois. Caso contrario, e escrito na tela uma mensagem # indicando a sintaxe correta, atribuindo-se o valor 1 ao codigo de # saida if [ $# -ne 2 ]; then echo 1>&2 Sintaxe: $0 arquivo_entrada arquivo_saida exit 1 # Caso o numero de argumentos esteja correto, executa-se entao # o programa else if [ -f $infile ]; then # A funcao deste if e verificar se o arquivo de entrada existe # Caso exista, entao e executado o comando, caso contrario, # o processamento e encerrado com uma mensagem de erro e ao codigo # de saida e atribuido o valor 1. sed -f $MACROS/tiraacento.sed $infile > $outfile else # Nunca se esqueca do aviso de erro. Caso contrario o usuario # do programa pode pensar que tudo deu certo. echo "$infile nao existe!!! " exit 1 fi fi ----------------------------------------------------- ********************************************************************************************** Atribuicao de Valores a Variaveis em Shell Scripts --------------------------------------------------------------------- Variaveis sao sequencias de letras, digitos ou underscores, comecando com uma letra ou underscore "_". A atribuicao de valor a uma variavel ira depender da shell sendo utilizada. Na Bourne shell e compativeis (sh), atribui-se o valor a uma variavel da seguinte forma: DATE=6jun60 A variavel DATE foi atribuido o valor 6jun60. Outra caracteristica extremamente util e atribuir o valor de comandos a variaveis. Por exemplo, suponhamos que queiramos que a variavel DATE assuma o valor da data corrente, no formato mmddyy: DATE=`date +%m%d%y` O comando date, como especificado acima, ira retornar o valor 052797, onde 05 indica o mes de maio, 27 o dia do mes e 97 o dia do ano. Importante notar as aspas invertidas "`". Ao se delimitar um comando por aspas invertidas voce esta indicando que esta interessado no resultado do comando, que por sua vez sera atribuido a variavel. Por exemplo, se desejassemos enviar uma mensagem a todos os usuarios de determinado computador: #!/bin/sh for user in `awk -F: '{print $1}' /etc/passwd` do mail -s "Aviso Importante" $user < mensagem.importante echo $user done O shell script acima, ira obter, com o auxilio do programa awk, uma listagem de todos os usuarios da maquina, enviando em seguida uma mensagem a todos eles. A variavel $user serao atribuidos tantos valores quantos os retornados pelo comando awk -F: '{print $1}' /etc/passwd Observar que, no shell script, o comando esta delimitado por aspas invertidas (`). Como os campos no arquivo /etc/passwd sao delimitados por ":", faz-se necessario a especificacao da diretiva "-F:" para que o comando awk possa selecionar corretamente a identificacao do usuario ($1, ou o primeiro campo). Na linha onde se envia a mensagem o caracter "<" indica que a mensagem a ser enviada encontra-se dentro do arquivo "mensagem.importante". O titulo da mensagem e informado atraves da diretiva "-s" seguida pelo valor "Aviso Importante". O comando "echo $user" e apenas informativo e serve para monitorar o progresso da execucao do comando. -------------------------------------- ********************************************************************************************** Argumentos em Shell Scripts (Bourne Shell) --------------------------------------------------------------------- A partir de hoje serao veiculadas algumas dicas sobre variaveis em Shell scripts juntamente com exemplos de utilizacao. Comecaremos com os argumentos passados na linha de comandos. Estes argumentos recebem o nome de variaveis posicionais e sao identificadas por $0, $1, $2, ... A variavel $0 indica o comando emitido. Por exemplo, no comando % ls a b c d a variavel $0 assume o valor "ls". A variavel $1 recebe o valor "a", a variavel $2 recebe o valor "b" e assim por diante. Esta variavel e bastante utilizada para se enviar avisos ao usuario quanto a sintaxe correta de uso de comandos. Por exemplo: echo "Sintaxe: $0 arquivo_entrada arquivo_saida" Se a linha acima se encontrasse em uma shell script chamada "chname" e a invocassemos sem especificar corretamente seus argumentos, receberiamos o seguinte aviso: Sintaxe: chname arquivo_entrada arquivo_saida ---------------------------------------- ********************************************************************************************** Argumentos em Shell Scripts (Bourne Shell) (1) --------------------------------------------------------------------- A partir de hoje serao veiculadas algumas dicas sobre variaveis em Shell scripts juntamente com exemplos de utilizacao. Comecaremos com os argumentos passados na linha de comandos. Estes argumentos recebem o nome de variaveis posicionais e sao identificadas por $0, $1, $2, ... A variavel $0 indica o comando emitido. Por exemplo, no comando % ls a b c d a variavel $0 assume o valor "ls". A variavel $1 recebe o valor "a", a variavel $2 recebe o valor "b" e assim por diante. $# Numero de argumentos fornecidos. Constitui uma norma de boa programacao verificar este valor no inicio da shell e emitir mensagem de erro caso incorreto. $* Todos os argumentos fornecidos como uma string separada por brancos. $? Codigo de retorno. Codigos de retorno iguais a zero indicam que o programa conseguiu executar sua tarefa com sucesso, ao passo que valores diferentes indicam algum tipo de erro. Este valor pode ser setado de dentro de uma shell atraves da diretiva "exit". $$ Identificacao do processo executando a shell. Bastante util para criacao de arquivos temporarios. ********************************************************************************************** Argumentos em Shell Scripts (Bourne Shell) (2) --------------------------------------------------------------------- $# Numero de argumentos fornecidos. Constitui uma norma de boa programacao verificar este valor no inicio da shell e emitir mensagem de erro caso incorreto. Por exemplo: #!/bin/sh if [ $# -ne 2 ]; then echo 1>&2 Sintaxe: $0 in out exit 1 fi No exemplo acima, se nao forem fornecidos dois argumentos e exibida uma mensagem de erro para o usuario e e setado o codigo de retorno com o valor 1 para indicar que houve um erro de processamento. ----------------------------- ********************************************************************************************** Argumentos em Shell Scripts (Bourne Shell) (3) --------------------------------------------------------------------- $? Codigo de retorno do ultimo comando executado. Codigos de retorno iguais a zero indicam que o programa conseguiu executar sua tarefa com sucesso, ao passo que valores diferentes indicam algum tipo de erro. Este valor pode ser setado de dentro de uma shell atraves da diretiva "exit". Por exemplo: if [ $? -eq 0 ]; then mv file file.old else mv file file.err fi No exemplo acima e testado o resultado do ultimo comando executado. Se for 0 (tudo ok) o arquivo chamado file e renomeado para file.old. Caso algum erro tenha ocorrido, o arquivo file e renomeado para file.err. --------------------------------------- ********************************************************************************************** Argumentos em Shell Scripts (Bourne Shell) (4) --------------------------------------------------------------------- $$ Identificacao do processo executando a shell. Bastante util para criacao de arquivos temporarios. Por exemplo: tmpfile=/tmp/file$$ sed -e "s/$DE/$FROM" $1 > $tmpfile mv $tmpfile $1 No exemplo acima, o arquivo fornecido como argumento na linha de comandos e editado pelo comando sed, onde todas as strings identificadas pela variavel $DE sao substituidas pela string identificada pela variavel $PARA e a saida e gravada no arquivo /tmp/file$$ ($tmpfile). Apos a execucao do comando sed o arquivo temporario e novamente gravado como $1 (arquivo original). ----------------------- ********************************************************************************************** Programacao Shell - Caracteres Especiais --------------------------------------------------------------------- Deve-se tomar cuidados especiais, na programacao shell, com os chamados caracteres especiais. Sao eles: ; & () ^ < > espacos, tabulacao e new-line Sao utilizados para encadear comandos (;), tarefas batch, etc. Para utilizar qualquer um destes caracteres em um contexto diferente de seu significado original, faz-se necessario precede-los por "\" (backslash ou barra invertida), ou delimita-los pelo caracter ". Por exemplo, se quisermos achar todos os caracteres iniciados por rubens, nao importa a terminacao, utilizamos o comando find da maneira abaixo: find / -name rubens\* -print ou find / -name "rubens*" -print O caracter "*", caso nao precedido pela "\" ou delimitado pelas aspas (") e interpretado pela shell em uso e nao pelo comando find, resultando em erro: % find . -name 97* -print find: missing conjunction Ja o comando: % find . -name 97\* -print funciona perfeitamente :-) ---------------------------------- ********************************************************************************************** Debugging shell scripts --------------------------------------------------------------------- Ao se invocar uma shell com a flag -x, serao exibidos todos os comandos executados, atribuicao de valores a variaveis, permitindo o acompanhamento do processamento e deteccao de eventuais falhas. Por exemplo, a shell --------------------------------------------------------------------- #!/bin/sh -x echo `date` --------------------------------------------------------------------- ira exibir a seguinte saida: