Curso de Shell - Aula IV
Por: Alex Borro ( 10/04/2001 )

Nesta aula vamos aprender sobre comandos de laço como o while, for, case e select. Eles nos permitem executar alguns comandos diversas vezes, sob determinadas condições e até montar menuzinhos para interagir com o usuário.

While

Este é provavelmente o comando de laço mais utilizado em programação. Seu entendimento é simples. Ele testa uma condição (como faz o IF) e executa um conjunto de comandos se esta condição for verdadeira. Após a execução desses comandos, ele torna a testar a condição e se esta for verdadeira, ele reexecuta os comandos e assim por diante.

Sua sintaxe é a seguinte:

while [ condição ]; 
do
comando 1;
comando 2;
...
done;

O parâmetro [ condição ] funciona exatamente igual ao do IF. Não voltarei a abortar os parâmetros condicionais pois eles já foram explicados na aula 3. Em caso de dúvida sobre isso, uma rápida revisão na aula 3 é suficiente.

Bom, vamos ao exemplo mais simples do While: um contador.

x = 0
While [  "$x" -le 10 ];
do
   echo "Execução número:  $x"?;
   x = $((x+1));
done;

Analisando:

Na primeira linha temos a condição: enquanto o valor da variável x ( $x ) for menor-igual ( -le ) a 10, faça: mostre "Execução número: " e o valor de x ($x). Faça x = x + 1. Isso no bash é feito pelo comando $(( )). Ele realiza operações algébricas com variáveis. No caso acima, estamos somando x + 1 e colocando o resultado no próprio x.

Preste atenção, que as linhas do While precisam de um ";" para terminar, exceto a que contém o "do", pois ele representa o começo do bloco de comandos.

Quando executamos o script acima, temos uma contagem de 1 até 10:

neo@matrix:~$ x=0; while [ "$x" -lt 10 ]; do x=$((x+1)); echo
"Execução número: $x"; done;
Execução número: 1
Execução número: 2
...
Execução número: 10
neo@matrix:~$ 

O While tem muita utilidade em programação, mas fica difícil dar exemplos usando somente ele, pois geralmente ele está associado a execução de outros programas e rotinas mais complexas.

Eu costumo usar ele, por exemplo, quando quero que o napster fique tentando conectar, pois quando ele vai tentar conectar o servidor e não consegue, ele simplesmente termina. Ai eu coloco o while testando a código de retorno dele (lembram da variável $? ) e enquanto estiver diferente de zero (o napster terminou com erro), ele fica executando o napster:

? = 1; while [ "$?" -ne "0" ]; do ./nap; done;

O comando "? = 1" tenta atribuir 1 a variável ?. Isso provoca um erro, pois a variável ? É somente de leitura. Isso é necessário para que ? Contenha algo diferente de 0, pois senão o While não executa a primeira interação.



For

O for é semelhante ao while usado como um contador. É necessário fornecer uma lista de nomes e ele executa os comandos para cada nome na lista. Parece meio confuso, mas é simples. Veja a sintaxe:

for <var> in <lista>; 
do
comandos
done;

O For associa o primeiro item da lista de nomes à variável <var> e executa os comandos. Em seguida, associa novamente o segundo item da lista à <var> e executa novamente os comandos... e assim por diante, até acabar a lista.

Veja o exemplo:

neo@matrix:~$ for x in Compra Venda Aluguel; do echo $x; done;
Compra
Venda
Aluguel

Ou seja, primeiro ele coloca "Compra" na variável x e executa os comandos, no caso, "echo $x", e assim por diante.

Podemos facilmente implementar um contador, usando em conjunto com o for, o programinha "seq". Ele simplesmente gera uma seqüência de números. Por exemplo, "seq 10" gera uma seqüência de 1 até 10. Assim, podemos usá-lo no for:

for x in $(seq 10); do echo $x; done;

Esse comando é semelhante ao contador implementado com o While. Primeiro o x vale 1 e o for executa os comandos. Depois x vale 2 e ele reexecuta os comandos...

Vamos usar o For para renomear os arquivo de um diretório, mudando todos os arquivo terminados em ".mp3" para ".mp3.bak".

for x in *; do 
   mv "$x" "${x}.bak"; 
done;

for x in *.mp3; do 
   if [ -e "$x" ]; 
     then mv "$x" "${x}.bak"; 
   fi; 
done;

No local de <lista> nos colocamos "*.mp3". Isso diz ao bash para expandir (transformar) ele na lista de arquivos terminados com ".mp3". Senão houver nenhum arquivo com essa terminação, o bash não faz nada, ficando para o for a string "*.mp3". Por isso precisamos do IF para testar se o arquivo existe.

Experimente no seu sistema.

echo *.mp3

Vai mostrar os arquivos no diretório atual com terminação mp3, mas sem quebra de linha entre eles, ou seja, um nome após o outro. Se não houver nenhum arquivo com terminação mp3, ele apenas vai mostrar "*.mp3".

Bom, voltando ao For, ele vai atribuir a "x" cada nome na lista de arquivos com terminação ".mp3" e executar os comandos seguintes.

Primeiro ele testa para ver se o arquivo existe ( if [ -e "$x" ]; ), e se existir, renomeia ele para o seu próprio nome acrescido de ".bak" ( ${x}.bak ).

Resumindo, o For faz isso: você fornece uma lista de nomes para ele e ele vai atribuindo esses nomes, em ordem e um por vez, à variável <var> e executa os comandos entre o "do" e o "done;".



Case

O Case está mais para um comando condicional do que para comando de laço, visto que ele não executa "loopings" como o While e o For.

Ele geralmente é utilizado como substituição de vários IFs.. Um exemplo clássico e muito utilizado é quando você precisa testar um parâmetro fornecido na linha de comando. O Case é utilizado desta forma em scripts de inicialização de serviços do sistema.

Vou mostrar a sintaxe em em seguida um script que inicialize/ reinicialize ou pare algum serviço (como o sendmail, apache, bind, etc).

Sintaxe:

case <parâmetro> in

   <opção 1>) 
                          <comandos 1>
                          ;;

    [opção 2] )
                          <comandos 2>
                          ;;
    * )
                          < comandos se não for nenhuma das
opções >
                         ;;
esac

Vamos as explicações. O Case pega a string fornecida em <parâmetro> e compara com <opção 1>. Se forem iguais, ele executa <comandos 1> e sai fora. Caso contrario, ele compara <parâmetro> com <opção 2> e assim por diante.

Caso <parâmetro> não seja igual a nenhuma das opções, ele executa os comandos da opção "*", se este existir.

Prestem atenção a alguns detalhes na sintaxe. Deve existir um ")" após cada opção e também um ";;" após todos os comandos de cada opção. Vejam o exemplo abaixo:

case "$1" in

 'start' )
                echo "Iniciando o serviço..."
                <comandos para iniciar o serviço>
                ;;
 'restart' )
                echo "Reinicializando o serviço..."
                <comandos para reinicializar o serviço>
                ;;
 'stop' )
                echo "Parando o serviço..."
                <comandos para parar o serviço>
                ;;
 *)
                echo "Opção invalida!"
                echo "As opções válidas são: 
start,   stop   e   restart"
                ;;
esac

O Case serve exatamente para isso, ou seja, evitar o teste de vários Ifs. No caso acima, teríamos que utilizar 3 Ifs. Mesmo se o primeiro já fosse verdadeiro, o bash iria testar o segundo e o terceiro, ou seja, ia perder tempo desnecessariamente. Já no case isso não acontece. Após entrar em uma opção e executar seus comandos, ele já pula fora do case sem testar as outras opções abaixo.



Select

O Select é um comando de laço que nos permite mostrar um pequeno menuzinho de opções para o usuário. Cada opção possui um número e para escolher, o usuário digita o número correspondente a opção desejada. Vejamos a sintaxe a seguir:

select <var> in <lista de opções>;
do
   <comandos>
done;

Como disse acima, o select vai mostrar as opções contidas em <lista de opções>, uma por linha, com um número na frente e espera que o usuário digite a opção desejada. Ao digitar a opção, o select atribui o nome da opção a variável <var> e executa os comandos. Para sair do select, é necessário executar o comando "break". Vamos a um exemplo:

select x in Iniciar Reiniciar Parar Sair; do
   echo "Opção Escolhida:  $x"
   if [ "$x" == "Sair" ]; then break; fi;
done;

Ou seja, se o usuário escolher alguma opção diferente de "Sair", o script apenas escreve a opção. Se for escolhida Sair, ele mostra a opção, entra no IF e executa o break, saindo do select.

É interessante combinar o Select com o Case. Vamos mostrar como ficaria aquele exemplo do case, de iniciar um serviço, utilizando o Select, para tornar o script interativo:

select x in Iniciar Reiniciar Parar Sair; do

   case "$x" in
    'Iniciar' )
                echo "                   Iniciando o
serviço..."
                ;;
    'Reiniciar' )
                echo "                   Reinicializando o
serviço..."
                ;;
    'Parar' )
                echo "                   Parando o serviço..."
                ;;
    'Sair'  )
                echo "                   Script encerrado."
                break
                ;;
    *)
                echo "                   Opção
inválida!"
                ;;
   esac
done;

Primeiramente o Select mostra um menuzinho:

1) Iniciar
2) Reiniciar
3) Parar
4) Sair
#? 

Quando o usuário digitar um número de opção, o select executa o case e este compara a variável x com suas opções. Se achar alguma, executa seus comandos, no caso um echo. Se o usuário escolher Sair, além do echo, ele executa o "break", que interrompe o select:

neo@matrix:~/test$ ./t
1) Iniciar
2) Reiniciar
3) Parar
4) Sair
#? 1
                   Iniciando o serviço...
1) Iniciar
2) Reiniciar
3) Parar
4) Sair
#? 5
                   Opção inválida!
1) Iniciar
2) Reiniciar
3) Parar
4) Sair
#? 4
                   Script encerrado.
neo@matrix:~/test$

Bom pessoal, acho que por hoje é só. ;-) Espero que vocês tenham pego a idéia de como funciona comandos de laços. Pelos menos sabendo a utilidade, sintaxe e como funcionam, quando surgir a necessidade, vocês já vão saber quais ferramentas usar.

Qualquer dúvida, sugestão, etc, podem me enviar um e-mail. Terei o maior prazer em responder. Até a próxima aula!



Copyright (C) 1999-2000 Linux Solutions