Prévia do material em texto
PROGRAMAÇÃO EM AMBIENTES DE REDES DE COMPUTADORES Maikon Lucian Lenz Estruturas de controle, seleção e repetição em Shell Script Linux Objetivos de aprendizagem Ao final deste texto, você deve apresentar os seguintes aprendizados: � Reconhecer as expressões condicionais em Shell Script Linux. � Descrever as estruturas de controle, seleção e repetição. � Comparar exemplos de scripts que utilizem as estruturas de controle, seleção e repetição na automação das tarefas. Introdução Em muitas situações, ações executadas de maneira sequencial não serão suficientes para determinar o comportamento adequado do sistema. Nesses casos, é preciso usar estruturas de controle, que condicionarão a execução ou não de determinado trecho de código com base no retorno de comandos ou no valor de algum conjunto de variáveis. Essas estruturas podem selecionar ou anular trechos de código, bem como repetir a execução criando mudanças no fluxo do programa. Para isso, você conhecerá as estruturas de controle if, for, while, until, case e select da linguagem Shell Script. 1 Estruturas de controle e expressões condicionais em Shell Script Um programa de computador qualquer é interpretado ou compilado obede- cendo a uma sequência preestabelecida a partir das regras determinadas pela linguagem utilizada (MANZANO; OLIVEIRA, 2019). Na maioria dos casos, tende-se a realizar a execução do código da esquerda para a direita e do topo para baixo, assim como costumamos ler e escrever um texto qualquer. Obviamente, alguns operadores, comandos ou palavras-chave também podem especificar diferentes critérios de precedência, modificando a ordem em que serão executados ou interpretados cada um dos elementos de uma instrução ou linha de programação. De modo genérico, mesmo em expressões matemáticas, podemos observar que alguns operadores têm prioridade quando comparados a outros, sobretudo pela necessidade de solucionar eventuais ambiguidades na execução dessas operações. Por exemplo, você deve saber que a expressão 5 + 3 * 2 resulta em 11 já que, apesar de o operador soma (+) aparecer primeiro, o operador de multiplicação (*) deve ser executado primeiro, seguindo a mesma ordem de precedência da matemática; do contrário, o resultado da expressão seria 16. Contudo, nem sempre a sequência natural de execução de um código, ainda que alterada conforme a prevalência de um ou outro operador, será suficiente para adequar a ordem das operações no código às nossas necessidades, princi- palmente por uma eventual necessidade de alterar essa ordem de acordo com alguma condição variável em diferentes momentos da execução. Em geral, os critérios de prevalência apenas terão efeito para uma única linha instrução, não tendo, portanto, qualquer relação com as demais. Logo, são necessárias estruturas específicas que delimitem a ordem e o momento de execução de diferentes trechos do código. A essas estruturas, que modificam a ordem de execução das diferentes instruções relacionadas em um programa, damos o nome de estruturas de controle, normalmente divididas em sequência (intrínseca ao programa), seleção e repetição (COSTA, 2010). As estruturas de seleção garantem ao programador a possibilidade de executar ou não um trecho de código dada uma combinação de condições normalmente expressas por variáveis e operadores de comparação (NEWHAM, 2005). No Shell Script, a estrutura de seleção mais simples é executada com o uso das palavras if, then, elif, else e fi. O termo if verifica se as condições elencadas entre ele e a estrutura de controle then são verdadeiras, situação que permite a execução das instruções entre o then e outra estrutura de controle que finalize o bloco de código relacionado à expressão condicional (NEWHAM, 2005). No código do Exemplo 1, caso o comando cd / seja executado com sucesso, será exibida a mensagem Raiz na tela. Vale lembrar que todos os exemplos estão formulados na linguagem Shell Script. Estruturas de controle, seleção e repetição em Shell Script Linux2 # Exemplo 1 – if/then/fi if cd / then echo 'Raiz' fi Antes de executar o comando echo 'Raiz', o programa precisa inicial- mente executar o comando cd / para determinar se este retorna um valor verdadeiro ou falso. Assim, o diretório atual é alterado e, na sequência, exibe-se a mensagem. Outros comandos que estivessem entre as palavras reservadas then e fi também seriam executados. É possível reescrever o mesmo código em uma única linha utilizando ponto e vírgula para separar os comandos, conforme o Exemplo 2. # Exemplo 2 – if/then/fi usando ";" if cd /; then echo 'Raiz'; fi Se o argumento / fosse substituído por um caminho inexistente, apenas a mensagem de erro do próprio cd seria exibida e o echo 'Raiz' seria ignorado. Nesse caso, em que o comando não pode ser finalizado com sucesso e, portanto, é compreendido como uma condição falsa, pode-se utilizar a palavra reservada else para indicar outro trecho de código a ser executado. No algo- ritmo do Exemplo 3, a mensagem Falhou será exibida caso não seja possível localizar o diretório utilizado de argumento (home) com o comando cd. É importante destacar que aquilo que é compreendido como um valor “verdadeiro” quando se utilizam comandos como condições é o valor de estado de saída (exit status). Se o valor retornado for 0, será compreendido como verdadeiro; qualquer outro valor será falso (ROBBINS; BEEBE, 2005). # Exemplo 3 – if/then/else/fi if cd home then echo 'Pasta Encontrada' else echo 'Falhou' fi 3Estruturas de controle, seleção e repetição em Shell Script Linux Antes da mensagem Falhou, no entanto, seria exibida a mensagem de erro do próprio comando cd (Figura 1). Figura 1. Resultado da execução do algoritmo do Exemplo 3. Há, ainda, uma quinta palavra reservada utilizada nessa estrutura de con- dicionamento iniciada com if e encerrada com fi: trata-se da palavra elif, empregada para verificar outras condições caso as anteriores sejam falsas. A partir do código do Exemplo 4, é fácil entender o funcionamento do elif. Caso o comando cd home (home com a letra inicial minúscula) retorne falso, será executado um novo comando cd Home (Home com a letra inicial maiúscula). Em qualquer um dos casos, o código após o then só será executado se as condições testadas forem verdadeiras. # Exemplo 4 – if/then/elif/else/fi if cd home then echo 'Alternativa 1 funcionou' elif cd Home then echo 'Alternativa 2 funcionou' fi Na existência de uma pasta home, será exibida a mensagem Alternativa 1 funcionou, mas, caso esta não exista, mas uma pasta Home exista, será exibida a mensagem Alternativa 2 funcionou. Se nenhum dos dois casos for verdadeiro, restariam somente as mensagens de erro de cada tentativa de executar o comando cd. Estruturas de controle, seleção e repetição em Shell Script Linux4 É possível incluir ainda mais condições elif, que serão testadas em sequência até que uma condição verdadeira ou o fim da estrutura condicional if [...] fi seja encontrada. Também sempre podemos encerrar com a condição else, que será executada caso nenhuma outra condição seja verdadeira. Ainda, pode-se combinar condições em um único teste por meio dos opera- dores &&, operação e (and), em que todas as condições devem ser verdadeiras; e ||, operação ou (or), em que pelo menos uma condição deve ser verdadeira (NEWHAM, 2005). O Exemplo 5 compara a busca de um texto em dois arquivos diferentes por meio de uma lógica E, em que a condição somente será interpretada como verdadeira caso os dois resultados encontrem o valor esperado. # Exemplo 5 – if/then/else/&& if grep "$var1" "$arquivo1" && grep "$var1" "$arquivo2" then echo 'Ambos os arquivos possuem a palavra.' else echo 'Pelo menos um dos arquivos não possui a palavra.' fi No Exemplo 5, a palavra contida na variável var1 deve ser encontrada tanto no arquivo da variável arquivo1 quanto do arquivo2 para que a primeira mensagem seja exibida.Do contrário a segunda mensagem será exibida. Caso o operador && fosse substituído pelo operador ||, seria necessário que apenas um arquivo (ou ambos) tivesse a palavra var1 (Figura 2). Figura 2. Resultado da execução do algoritmo do Exemplo 5. 5Estruturas de controle, seleção e repetição em Shell Script Linux Comparações e expressões aritméticas também podem ser utilizadas como condições de teste (Exemplo 6). Porém, uma vez que as estruturas de controle do Shell Script apenas compreendem estados de saída, é necessário encapsu- lar esses testes entre colchetes, que retornarão um valor de saída a partir do resultado da expressão (ROBBINS; BEEBE, 2005). # Exemplo 6 – if/then/[] A=5 if [ $A -ge 4 ] then echo 'A variável A é maior que 4' fi O Quadro 1 relaciona os testes mais comuns para comparar e verificar valores inteiros, textos, arquivos e diretórios. Teste Exemplo Verdadeiro quando Condições entre strings/textos = [ $str1 = $str2 ] str1 e str2 são iguais != [ $str1 != $str2 ] str1 e str2 são diferentes < [ $str1 > $str2 ] str1 é maior que str2 > [ $str1 < $str2 ] str1 é menor que str2 -n [ -n $str1 ] str1 é nulo -z [ -z $str1 ] str1 não é nulo Condições entre arquivos e pastas -a [ -a $arq1 ] arq1 existe -d [ -d $arq1 ] arq1 existe e é um diretório -e [ -e $arq1 ] arq1 existe -f [ -f $arq1 ] arq1 existe e é um arquivo -r [ -r $arq1 ] arq1 tem permissão de leitura Quadro 1. Testes condicionais mais comuns entre strings, arquivos e inteiros (Continua) Estruturas de controle, seleção e repetição em Shell Script Linux6 Fonte: Adaptado de Newham (2005). Teste Exemplo Verdadeiro quando Condições entre arquivos e pastas -s [ -s $arq1 ] arq1 existe, mas não está vazio -w [ -w $arq1 ] arq1 tem permissão de leitura -x [ -x $arq1 ] arq1 pode ser executado/pesquisado -N [ -N $arq1 ] arq1 modificado após última leitura -O [ -O $arq1 ] arq1 pertence ao usuário atual -G [ -G $arq1 ] arq1 pertence ao seu grupo -nt [ $arq1 -nt $arq2 ] arq1 é mais novo que arq2 -ot [ $arq1 -ot $arq2 ] arq1 é mais antigo que arq2 Condições entre inteiros -lt [ $A -lt $B ] A for menor que B -le [ $A -le $B ] A for menor ou igual a B -eq [ $A -eq $B ] A for igual a B -ge [ $A -ge $B ] A for maior ou igual B -gt [ $A -gt $B ] A for maior que B -ne [ $A -ne $B ] A for diferente de B Quadro 1. Testes condicionais mais comuns entre strings, arquivos e inteiros (Continuação) Ao executar qualquer uma das condições do Quadro 1, serão retornados o valor 0, no caso de a condição ser verdadeira, e 1, para as demais situações. Assim, podemos utilizar essas operações de comparação em conjunto com as estruturas de controle if/elif. 7Estruturas de controle, seleção e repetição em Shell Script Linux Um método novo para efetuar um teste de condições se dá com colchetes duplos [[...]], que tem a vantagem, entre outras, de possibilitar o uso de expressões regulares no condicionamento. Já o método antigo [...] permanece disponível e garante portabilidade em relação a versões antigas (NEWHAM, 2005). 2 Estruturas de repetição em Shell Script As estruturas de repetição em Shell Script possibilitam que o programador repita um trecho de código enquanto uma combinação de condições é aten- dida, o que normalmente se avalia com o auxílio de expressões lógicas entre variáveis e/ou constantes (NEWHAM, 2005). O laço de repetição mais simples é o for, por meio do qual podemos executar um trecho de código a quantidade de vezes determinada pela con- dição associada. No for, a quantidade de execuções é previamente conhecida, já que deve ser fornecida uma lista de valores a serem iterados pelo laço, conforme a estrutura demonstrada no Exemplo 7. # Exemplo 7 – for/in/do/done $lista='Palavra1 Palavra2' for var in $lista do echo $var done O Exemplo 7 escreveria Palavra1 primeiro e Palavra2 na sequência em outra linha, já que a variável lista pode ser compreendida como uma lista de palavras. Estruturas de controle, seleção e repetição em Shell Script Linux8 Suponhamos que a variável lista tivesse nomes de arquivos, cuja existência fosse necessário verificar. Seria possível combinar uma estrutura de repetição como o for para executar um teste condicional em cada um desses nomes, como mostrado no Exemplo 8. # Exemplo 8 – for/in/do/done/if/else lista="/mnt/c/Sagah/arquivo1 /mnt/c/Sagah/arquivo2" for var in $lista do if [ -a $var ] then echo "O arquivo $var existe" else echo "O arquivo $var não existe" fi done Cada um dos caminhos da string lista é testado: inicialmente, o caminho para o arquivo1, e, depois, o caminho para o arquivo2. Para cada teste, exibe-se a mensagem se o arquivo existe ou não (Figura 3). Figura 3. Resultado da execução do algoritmo do Exemplo 8 contido no arquivo arq e invocado pelo comando source. Em resumo, a variável var assume o valor de cada item da lista na exata ordem em que aparecem; no caso de uma string, cada conjunto de caracteres separados por um espaço (BLUM, 2008). É possível alterar o caractere que demarca a separação entre itens de uma variável, pois quem define é o valor da variável IFS. 9Estruturas de controle, seleção e repetição em Shell Script Linux No Exemplo 9, o IFS foi alterado para que a variável lista possa ser iterada, já que os itens não foram separados por meio de um espaço. # Exemplo 9 – for/in/do/done/if/else $lista="~/Downloads/arquivo1\n~/Downloads/arquivo2" IFS _ BACKUP=$IFS IFS=$'\n' for var in $lista do if [ -a $var ] then echo "O arquivo $var existe" else echo "O arquivo $var, não existe" fi done IFS=$IFS _ BACKUP O Exemplo 9 executa a mesma operação do Exemplo 8, porém utilizando uma lista de caminhos/nomes dos arquivos que estão separados por uma nova linha (\n). Para tanto, o IFS é alterado, mas não sem antes efetuar uma cópia do IFS antigo, que pode ser restaurado ao final do laço de repetição Como o IFS é importante para inúmeros comandos, alterá-lo pode comprometer o funcionamento adequado do código. Assim, deve-se tomar o cuidado de sempre restaurar o seu valor original quando da conclusão da tarefa necessária. Representa uma boa prática de programação somente alterar o IFS imediatamente antes de ser utilizado e restaurar o seu valor original tão logo não seja mais necessária a mudança (BLUM, 2008). Outra estrutura de repetição ainda mais flexível é o laço while, por meio do qual um trecho de código é executado enquanto as condições que definem o laço forem verdadeiras, ou seja, receberem o estado de saída igual a 0 (BLUM, 2008). Estruturas de controle, seleção e repetição em Shell Script Linux10 Assim como no for, o trecho de código a ser executado é precedido por uma palavra do e encerrado por uma palavra done, como no Exemplo 10. # Exemplo 10 – while/do/done conta=10 while [ $conta -gt 0 ] do echo $conta conta=$[ $conta – 1 ] done O Exemplo 10 exibe o valor da variável conta no console enquanto esta for maior que 0. Ao final de cada iteração, o valor da variável conta é reduzido em 1 unidade, resultando em 10 mensagens do valor 10 até o valor 1, conforme a Figura 4. Figura 4. Resultado da execução do algoritmo do Exemplo 11. Caso fosse utilizado um comando ou teste que nunca tivesse seu valor alterado, o algoritmo ficaria preso em um laço infinito. 11Estruturas de controle, seleção e repetição em Shell Script Linux Outra estrutura com a mesma finalidade de repetição condicionada é o laço until, cuja única diferença reside no fato de que espera um estado de saída 0, ou verdadeiro, para encerrar a repetição (BLUM, 2008). O Exemplo 11 tem o mesmo efeito do Exemplo 10, porém o laço while foi substituído por um laço until e, para manter a mesma funcionalidade, foi preciso alterar o teste de -gt para -eq, ou seja, no lugar de comparar se a variável conta é maior que 0, o laço until verifica se a variável é igual a 0. # Exemplo 11 –until/do/done conta=5 until [ $conta -eq 0 ] do echo $conta conta=$[ $conta – 1 ] done Independentemente do laço de repetição utilizado, é possível influenciar na continuidade da iteração ou da execução do trecho de código por meio dos comandos break e continue. No Exemplo 12, cada um dos números da lista é exibido desde que não seja detectado o número 5. Nesse caso, o loop é encerrado com o uso do comando break. # Exemplo 12 – break command for var in 1 3 5 7 9 do if [ $var -eq 5 ] then break else echo $var fi done Estruturas de controle, seleção e repetição em Shell Script Linux12 Pode-se alterar o comportamento do Exemplo 12 para que todos os números sejam exibidos, exceto o número 5, utilizando o comando continue, que forçará o término da iteração atual. # Exemplo 13 – continue command for var in 1 3 5 7 9 do if [ $var -eq 5 ] then continue fi echo $var done Obviamente, os Exemplos 12 e 13 poderiam ser solucionados de diversas outras maneiras sem necessitar recorrer aos comandos break e continue, respectivamente. Mas resta evidente que, apesar das regras utilizadas nas condições da estrutura de repetição, ainda é possível controlar o progresso das iterações de dentro do trecho de código do laço. 3 Estruturas de seleção em Shell Script Muitas vezes, são necessários vários testes e condições para determinar qual o trecho de código será executado na sequência. Na linguagem Shell Script, pode-se recorrer ao método convencional de implementar inúmeros testes if-else, ou combinações de if-elif, no entanto, além de o código ficar demasiadamente extenso, torna-se pouco legível e difícil de manter. O Exemplo 14 mostra uma dessas situações, em que vários testes são ne- cessários para selecionar o codec adequado na manipulação de um arquivo de áudio. 13Estruturas de controle, seleção e repetição em Shell Script Linux # Exemplo 14 if [[ $arquivo == *.mp3 ]] then mp3codec $arquivo elif [[ $arquivo == *.wma ]] then wmacodec $arquivo elif [[ $arquivo == *.ogg ]] then oggcodec $arquivo else echo 'Formato inválido!' fi O teste interno aos colchetes duplos utiliza uma expressão regular para verificar se o nome do arquivo tem a extensão mp3, wma ou ogg para, a partir dessa informação, acionar o codec adequado para cada tipo de arquivo. Do contrário, é exibida uma mensagem alertando para um formato de arquivo inválido. O Exemplo 15 faz exatamente o mesmo processo, porém com o uso da estrutura de case. # Exemplo 15 – case case $arquivo in *.mp3) mp3codec $arquivo break ;; *.wma) wmacodec $arquivo break ;; *.ogg) oggcodec $arquivo break ;; *) echo 'Formato inválido!' ;; break ;; esac A variável a ser testada, entre as palavras case e in, é comparada com cada um dos padrões delimitados pelo finalizador “)” — o primeiro que for atendido é executado (ALBING; VOSSEN, 2017). Apesar de a estrutura se assimilar muito à do if-elif, o case normal- mente resulta em um código mais legível e de menor tamanho. Além disso, Estruturas de controle, seleção e repetição em Shell Script Linux14 com o case é possível executar múltiplas condições, desde que estas sejam atendidas. Para evitar que a execução em mais de uma condição, pode-se usar o break, que interromperá os testes das demais opções. Assim, é possível controlar se se pretende executar todos os padrões que forem atendidos, um conjunto deles ou até mesmo somente o primeiro que ocorrer, como o caso do Exemplo 15. Para exibir a mensagem de erro caso nenhum padrão de extensão do arquivo seja encontrado, emprega-se um padrão que atende a qualquer situação (*), forçando a última opção a ser executada caso nenhuma outra tenha ocorrido. Por fim, a última estrutura de controle é o select, utilizado para criar menus de opções de forma rápida e prática. O código entre o do e o done da estrutura select é repetido enquanto o usuário não informar um índice válido, que corresponda às opções exibidas. O índice 1 se refere ao primeiro item da lista fornecida pela estrutura select (após o termo in) e cada uma das opções é separada por um espaço vazio. Caso fosse necessário um texto contendo espaços, cada um dos itens a ser iterados deveria estar delimitado entre aspas duplas. No Exemplo 16, é exibida uma lista de opções — Arquivo, Editar e Formatar —, numeradas de 1 a 3 nessa mesma ordem. O programa somente tem continuidade após o usuário digitar algum valor e pressionar a tecla ENTER, ou seja, retornando algum valor para o console. # Exemplo 16 – select select menu in Arquivo Editar Formatar do if [ -n "$menu" ] then echo "Abrindo menu $menu" break else echo "Opção inválida" fi done Caso o número digitado esteja entre 1 e 3, a mensagem informando qual o respectivo menu selecionado é exibida. Do contrário, somente é mostrada a mensagem Opção inválida, como visualizado na Figura 5, em que o arquivo seca contém o código em Shell Script do Exemplo 16. 15Estruturas de controle, seleção e repetição em Shell Script Linux Figura 5. Uso da estrutura select do Exem- plo 16 contido no arquivo seca e invocado pelo comando source. Ao utilizarmos essas estruturas de controle de fluxo, podemos criar so- luções muito mais dinâmicas e scripts mais fáceis de compreender, o que é especialmente importante quando o código se torna muito grande ou requer alterações e atualizações constantes. Com exceção das estruturas de sequenciamento, intrínsecas à execução do programa, as estruturas de seleção e repetição são livremente utilizadas pelo programador e dependem diretamente das necessidades e da lógica construída. É importante destacar que, apesar dos exemplos demonstrados, a maioria dos casos pode ser solucionada de maneiras diversas, não sendo as resoluções apresentadas, portanto, as únicas possíveis para os exemplos citados. Somente após a compreensão do funcionamento desses mecanismos o programador poderá escolher de maneira eficaz entre um ou outro método de resolução. ALBING, C.; VOSSEN, J. P. bash cookbook: solutions and examples for bash users. Sebas- topol: O’Reilly, 2017. 726 p. BLUM, R. Linux command line and shell scripting. Indianapolis: Wiley, 2008. 840 p. COSTA, D. G. Administração de redes com scripts: Bash Script, Python e VBScript. 2. ed. Rio de Janeiro: Brasport, 2010. 172 p. MANZANO, J. A. M. G.; OLIVEIRA, J. F. Algoritmos: lógica para desenvolvimento de programação de computadores. 29. ed. São Paulo: Érica, 2019. 368 p. NEWHAM, C. Learning the bash shell: Unix shell programming. 3. ed. Sebastopol: O’Reilly, 2005. 352 p. ROBBINS, A.; BEEBE, N. H. F. Classic shell scripting: automate your Unix tasks. 3. ed. Sebastopol: O’Reilly, 2005. 558 p. Estruturas de controle, seleção e repetição em Shell Script Linux16