Baixe o app para aproveitar ainda mais
Prévia do material em texto
Capítulo 9 - Scripts básicos 9.1 Introdução Neste capítulo, vamos discutir como as ferramentas que aprendeu até agora podem ser transformadas em scripts reutilizáveis. 9.2 Shell Scripts em poucas palavras Um script de shell é um arquivo de comandos executáveis que foi armazenado em um arquivo de texto. Quando o arquivo é executado, cada comando é executado. Os scripts de shell têm acesso a todos os comandos do shell, incluindo a lógica. Um script pode, portanto, testar a presença de um arquivo ou procurar resultados específicos e alterar seu comportamento de acordo. Você pode criar scripts para automatizar partes repetitivas do seu trabalho, o que libera seu tempo e garante consistência cada vez que você usa o script. Por exemplo, se você executar os mesmos cinco comandos todos os dias, pode transformá-los em um script de shell que reduz seu trabalho para um comando. Um script pode ser tão simples como um comando: echo “Hello, World!” O script, test.sh, consiste apenas em uma linha que imprime a linha Hello, World! para o console. Executar um script pode ser feito passando-o como um argumento para o seu shell ou executando-o diretamente: sysadmin@localhost:~$ sh test.sh Hello, World! sysadmin@localhost:~$ ./test.sh -bash: ./test.sh: Permission denied sysadmin@localhost:~$ chmod +x ./test.sh sysadmin@localhost:~$ ./test.sh Hello, World! No exemplo acima, primeiro, o script é executado como um argumento para o shell. Em seguida, o script é executado diretamente do shell. É raro ter o diretório atual no caminho de pesquisa binário $PATH, então o nome é prefixado com ./ para indicar que ele deve ser executado fora do diretório atual. O erro Permissão negada significa que o script não foi marcado como executável. Um rápido chmod mais tarde e o script funciona. Chmod é usado para alterar as permissões de um arquivo, que será explicado em detalhes em um capítulo posterior. Existem vários shells com sua própria sintaxe de idioma. Portanto, scripts mais complicados irão indicar um shell específico, especificando o caminho absoluto para o intérprete como a primeira linha, prefixada por #! como mostrado: #!/bin/sh echo “Hello, World!” ou #!/bin/bash echo “Hello, World!” Os dois personagens, #! são tradicionalmente chamados de hash e bang, respectivamente, o que leva à forma abreviada de "shebang" quando eles são usados no início de um script. Aliás, o shebang (ou crunchbang) é usado para scripts de shell tradicionais e outros idiomas baseados em texto, como Perl, Ruby e Python. Qualquer arquivo de texto marcado como executável será executado sob o interpretador especificado na primeira linha, desde que o script seja executado diretamente. Se o script for invocado diretamente como um argumento para um intérprete, como sh script ou bash script, o shell fornecido será usado, não importa o que esteja na linha shebang. Isso ajuda a se sentir confortável usando um editor de texto antes de escrever scripts de shell, pois você precisará criar arquivos em texto simples. As ferramentas de escritório tradicionais como o LibreOffice que produzem formatos de arquivo que contenham formatação e outras informações não são apropriadas para esta tarefa. 9.3 Editando Scripts Shell UNIX tem muitos editores de texto, os méritos de um sobre o outro muitas vezes são muito debatidos. Dois são especificamente mencionados no LPI Essentials syllabus: o editor GNU nano é um editor muito simples, bem adaptado para editar pequenos arquivos de texto. O Visual Editor, VI, ou a versão mais recente, VI melhorado (VIM), é um editor notavelmente poderoso, mas tem uma curva de aprendizado íngreme. Nós nos focaremos em nano. Digite nano test.sh e você verá uma tela semelhante a esta: GNU nano 2.2.6 File: test.sh modified #!/bin/sh echo "Hello, World!" echo -n "the time is " date ^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut Text ^C Cur Po ^X Exit ^J Justify ^W Where Is ^V Next Page ^U UnCut Text^T To Spell O editor nano tem poucos recursos para você chegar no seu caminho. Você simplesmente digita com seu teclado, usando as teclas de seta para mover-se e o botão delete/backspace para excluir o texto. Ao longo da tela, você pode ver alguns comandos disponíveis para você, que são sensíveis ao contexto e mudam dependendo do que você está fazendo. Se você estiver diretamente na própria máquina Linux, ao contrário de se conectar à rede, você também pode usar o mouse para mover o cursor e destacar o texto. Para se familiarizar com o editor, comece a digitar um script de shell simples enquanto estiver dentro de nano: GNU nano 2.2.6 File: test.sh modified #!/bin/sh echo "Hello, World!" echo -n "the time is " date ^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut Text ^C Cur Po ^X Exit ^J Justify ^W Where Is ^V Next Page ^U UnCut Text^T To Spell Observe que a opção inferior esquerda é ^X Sair, que significa "pressionar Ctrl e X para sair". Pressione Ctrl e X juntos e a parte inferior muda: Save modified buffer (ANSWERING "No" WILL DESTROY CHANGES) ? Y Yes N No ^C Cancel Neste ponto, você pode sair do programa sem salvar pressionando a tecla N, ou salve primeiro pressionando Y para salvar. O padrão é salvar o arquivo com o nome do arquivo atual. Você pode pressionar a tecla Enter para salvar e sair. Você estará de volta no prompt do shell depois de salvar. Retorne ao editor. Desta vez, pressione Ctrl e O juntos para salvar seu trabalho sem sair do editor. Os prompts são em grande parte os mesmos, exceto que você está de volta no editor. Desta vez, use as teclas de seta para mover o cursor para a linha que tem "the time is". Pressione Ctrl e K duas vezes para cortar as duas últimas linhas para o buffer de cópia. Mova o cursor para a linha restante e pressione Ctrl e U uma vez para colar o buffer de cópia para a posição atual. Outros comandos úteis que você pode precisar são: Comando Descrição Ctrl + W Localizar no documento Ctrl + W, then Control + R Localizar e Substituir Ctrl + G Ver todos os comandos possíveis Ctrl + Y/V Subir/Descer página Ctrl + C Mostra a posição atual no arquivo e o tamanho do arquivo 9.4 Scripts Básicos Você obteve seu primeiro gosto de script anteriormente neste capítulo, onde apresentamos um script muito básico que gerou um único comando. O script começou com a linha shebang, dizendo ao Linux que /bin/bash (que é Bash) deve ser usado para executar o script. Além de executar comandos, existem 3 tópicos com os quais você deve se familiarizar: Variáveis, que possuem informações temporárias no script Condicionais, que permitem que você faça coisas diferentes com base em testes que você escreve Loops, que permitem que você faça a mesma coisa uma e outra vez 9.4.1 Variáveis Asvariáveis são uma parte fundamental de qualquer linguagem de programação. Um uso muito simples de variáveis é mostrado aqui: #!/bin/bash ANIMAL="penguin" echo "My favorite animal is a $ANIMAL" Depois que a linha shebang é uma diretiva para atribuir algum texto a uma variável. O nome da variável é ANIMAL e o sinal de igual que atribui o penquin. Pense em uma variável como uma caixa na qual você pode armazenar coisas. Depois de executar esta linha, a caixa chamada ANIMAL contém a palavra penguin. É importante que não existam espaços entre o nome da variável, o sinal igual e o item a ser atribuído à variável. Se você tiver um espaço lá, você receberá um erro estranho como "comando não encontrado". Não é necessário capitalizar o nome da variável, mas é uma convenção útil para separar as variáveis dos comandos a serem executados. Em seguida, o script mostra uma string para o console. A string contém o nome da variável precedida de um sinal de dólar. Quando o intérprete vê o sinal de dólar, ele reconhece que irá substituir o conteúdo da variável, isso se chama interpolação. A saída do script é então “My favorite animal is a penguin”. Então lembre disso: para atribuir a uma variável, basta usar o nome da variável. Para acessar o conteúdo da variável, prefira-a com um sinal de dólar. Aqui, mostramos uma variável atribuída aos conteúdos de outra variável! #!/bin/bash ANIMAL=penguin SOMETHING=$ANIMAL echo "My favorite animal is a $SOMETHING" ANIMAL contém o penguin (como não há espaços, a sintaxe alternativa sem usar cotações é mostrada). SOMETHING é então designado o conteúdo de ANIMAL (porque ANIMAL tem o sinal de dólar em frente a ele). Se você quisesse, você poderia atribuir uma string interpolada a uma variável. Isso é bastante comum em scripts maiores, pois você pode criar um comando maior e executá-lo! Outra maneira de atribuir a uma variável é usar a saída de outro comando como o conteúdo da variável ao encerrar o comando nos tiques de volta: #!/bin/bash CURRENT_DIRECTORY=`pwd` echo "You are in $CURRENT_DIRECTORY" Esse padrão geralmente é usado para processar texto. Você pode pegar texto de uma variável ou um arquivo de entrada e passar por outro comando como sed ou awk para extrair certas partes e manter o resultado em uma variável. É possível obter entrada do usuário do seu script e atribuí-lo a uma variável através do comando de leitura: #!/bin/bash echo -n "What is your name? " read NAME echo "Hello $NAME!" O comando de leitura pode aceitar uma string diretamente do teclado ou como parte do redirecionamento de comando, como você aprendeu no último capítulo. Existem algumas variáveis especiais para além das que você definiu. Você pode passar argumentos para o seu script: #!/bin/bash echo "Hello $1" Um sinal de dólar seguido por um número N corresponde ao N° argumento passado ao script. Se você chamar o exemplo acima com ./test.sh, a saída será Hello Linux. A variável $0 contém o nome do próprio script. Depois que um programa é executado, seja um binário ou um script, ele retorna um código de saída que é um número inteiro entre 0 e 255. Você pode testar isso através da variável $? para ver se o comando anterior foi concluído com sucesso. sysadmin@localhost:~$ grep -q root /etc/passwd sysadmin@localhost:~$ echo $? 0 sysadmin@localhost:~$ grep -q slartibartfast /etc/passwd sysadmin@localhost:~$ echo $? 1 O comando grep foi usado para procurar uma string dentro de um arquivo com a bandeira -q, que significa "silencioso". O grep, enquanto corre em modo silencioso, retorna 0 se a sequência for encontrada e 1 caso contrário. Esta informação pode ser usada em um condicional para executar uma ação com base na saída de outro comando. Da mesma forma, você pode definir o código de saída do seu próprio script com o comando de saída: #!/bin/bash # Something bad happened! exit 1 O exemplo acima mostra um comentário #. Qualquer coisa após a marca de hash é ignorada, o que pode ser usado para ajudar o programador a deixar notas. A saída 1 retorna o código de saída 1 para o chamador. Isso funciona mesmo no shell, se você executar este script a partir da linha de comando e digite echo $? Você verá que retorna 1. Por convenção, um código de saída de 0 significa "tudo está OK". Qualquer código de saída maior que 0 significa que algum tipo de erro ocorreu, o que é específico para o programa. Acima você viu que grep usa 1 para significar que a string não foi encontrada. 9.4.2 Condições Agora que você pode olhar e definir variáveis, é hora de fazer seu script fazer funções diferentes com base em testes, chamados de ramificação. A instrução if é o operador básico para implementar ramificação. Uma instrução básica se parece com isto: if somecommand; then # do this if somecommand has an exit code of 0 fi O próximo exemplo executará "somecommand" (na verdade, tudo até o ponto-e-vírgula) e se o código de saída for 0, então o conteúdo até o encerramento será executado. Usando o que você conhece sobre o grep, agora você pode escrever um script que faça coisas diferentes com base na presença de uma string no arquivo de senha: #!/bin/bash if grep -q root /etc/passwd; then echo root is in the password file else echo root is missing from the password file fi Nos exemplos anteriores, você pode lembrar que o código de saída do grep é 0 se a string for encontrada. O exemplo acima usa isso em uma linha para imprimir uma mensagem se o root estiver no arquivo de senha ou uma mensagem diferente se não for. A diferença aqui é que, ao invés de um encerramento do bloco if, há outra coisa. Isso permite que você faça uma ação se a condição for verdadeira e outra se a condição for falsa. O bloco else ainda deve ser fechado com a palavra-chave. Outras tarefas comuns são procurar a presença de um arquivo ou diretório e comparar cadeias e números. Você pode inicializar um arquivo de log se não existir ou comparar o número de linhas em um arquivo até a última vez que você o executou. O comando if é claramente aquele para ajudar aqui, mas qual comando você usa para fazer a comparação? O comando de teste oferece acesso fácil a operadores de teste de comparação e arquivo. Por exemplo: Comando Descrição test –f /dev/ttyS0 0 se o arquivo existe test ! –f /dev/ttyS0 0 se o arquivo não existe test –d /tmp 0 se o diretório existe test –x `which ls` substitua a localização de ls e teste se o usuário pode executar test 1 –eq 1 0 se a comparação numérica for bem sucedida test ! 1 –eq 1 NOT – 0 se a comparação falhar test 1 –ne 1 Mais fácil, teste de desigualdade numérica test “a” = “a” 0 se as strings forem iguais test “a” != “a” 0 se as strings forem diferentes test 1 –eq 1 –o 2 –eq 2 -o é OU: ou pode ser o mesmo test 1 –eq 1 –a 2 –eq 2 -a é AND: ou pode ser o mesmo É importante notar que o teste analisa as comparações inteiras e de cordas de forma diferente. 01 e 1 são iguais por comparação numérica, mas não por comparação de string. Você deve sempre ter cuidado para lembrar o tipo de entrada que você espera. Há muitos mais testes, como -gt para maiores que, maneiras de testar se um arquivo é mais novo que o outro e muitos mais. Consulte a página do manual de teste para obter mais informações. O teste é bastante detalhado para um comando que se usa com tanta frequência, então há um alias para isso chamado [ (suporte quadrado esquerdo). Se você encerrar suas condições entre colchetes, é o mesmo que executar o teste. Então, essas declarações são idênticas. if test –f /tmp/foo; then if [ -f /tmp/foo]; then Embora a última forma seja usada com mais frequência, é importante entender que o suporte quadrado é um comando por conta própria que funciona de forma semelhante ao teste, exceto que requer o suporte quadrado de fechamento. A instrução if tem uma forma final que permite que você faça várias comparações ao mesmo tempo usando elif (abreviação de else if). #!/bin/bash if [ "$1" = "hello"]; then echo "hello yourself" elif [ "$1" = "goodbye" ]; then echo "nice to have met you" echo "I hope to see you again" else echo "I didn't understand that" fi O código acima compara o primeiro argumento passado ao script. Se é hello, o primeiro bloco é executado. Caso contrário, o script verifica se é goodbye e exibe uma mensagem diferente, se assim for. Caso contrário, uma terceira mensagem é enviada. Observe que a variável $1 é citada e o operador de comparação de cadeias é usado em vez da versão numérica (-eq). Os testes if/elif/else podem se tornar bastante detalhados e complicados. A afirmação do caso fornece uma maneira diferente de tornar múltiplos testes mais fáceis. #!/bin/bash case "$1" in hello|hi) echo "hello yourself" ;; goodbye) echo "nice to have met you" echo "I hope to see you again" ;; *) echo "I didn't understand that" esac A declaração do caso começa com uma descrição da expressão que está sendo testada: case EXPRESSION in. A expressão aqui é $1. Em seguida, cada conjunto de testes é executado como uma partida de padrão terminada por um parêntese de fechamento. O exemplo anterior primeiro olha para hello ou hi; múltiplas opções são separadas pela barra vertical | que é um operador de OR em muitas linguagens de programação. Seguindo a seguir, são os comandos a serem executados se o padrão retornar verdadeiro, que são terminados por dois pontos-e-volta. O padrão se repete. O padrão * é o mesmo que outro porque ele combina com qualquer coisa. O comportamento da declaração do caso é semelhante à instrução if/elif/else em que o processamento para após a primeira partida. Se nenhuma das outras opções corresponder ao * garanta que o último corresponda. Com uma sólida compreensão dos condicionais, você pode fazer seus scripts tomar ações somente se necessário. 9.4.3 Loops Loops permitem que o código seja executado repetidamente. Eles podem ser úteis em várias situações, como quando você deseja executar os mesmos comandos em cada arquivo em um diretório ou repetir algumas ações 100 vezes. Existem dois loops principais em scripts de shell: o loop for e o loop while. Loops for são usados quando você possui uma coleção finita sobre a qual deseja iterar, como uma lista de arquivos ou uma lista de nomes de servidores: #!/bin/bash SERVERS="servera serverb serverc" for S in $SERVERS; do echo "Doing something to $S" done O primeiro script configura uma variável contendo uma lista separada de nomes de servidores. A instrução for, em seguida, faz o percurso da lista de servidores, cada vez que ele define a variável S para o nome do servidor atual. A escolha de S foi arbitrária, mas note que o S não tem sinal de dólar, mas os $SERVERS, mostrando que $SERVERS será expandido para a lista de servidores. A lista não precisa ser uma variável. Este exemplo mostra duas maneiras mais de passar uma lista. #!/bin/bash for NAME in Sean Jon Isaac David; do echo "Hello $NAME" done for S in *; do echo "Doing something to $S" done O primeiro loop é funcionalmente o mesmo que o exemplo anterior, exceto que a lista é passada para o loop for diretamente em vez de usar uma variável. Usar uma variável ajuda a clareza do script, pois alguém pode facilmente fazer alterações na variável ao invés de procurar um loop. O segundo loop usa um * que é um arquivo glob. Isso é expandido pelo shell para todos os arquivos no diretório atual. O outro tipo de loop, um loop while, opera em uma lista de tamanho desconhecido. Seu trabalho é continuar funcionando e, em cada iteração, realizar um teste para ver se ele deve ser executado em outro momento. Você pode pensar nisso como "enquanto alguma condição é verdadeira, faça coisas". #!/bin/bash i=0 while [ $i -lt 10 ]; do echo $i i=$(( $i + 1)) done echo “Done counting” O exemplo acima mostra um ciclo de tempo que conta de 0 a 9. Uma variável de contador, i, é inicializada para 0. Então um ciclo de tempo é executado com o teste sendo "$i é menor que 10?" Observe que o loop while usa a mesma notação como uma afirmação if! Dentro do loop while, o valor atual de i é exibido e, em seguida, 1 é adicionado a ele através do comando $ ((aritmética)) e atribuído de volta para i. Uma vez que eu me torne 10, a declaração while retorna falsa e o processamento continua após o loop.
Compartilhar