Por: Alex Borro
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 in ;
do
comandos
done;
O For associa o primeiro item da lista de nomes à variável e executa os comandos. Em seguida, associa novamente o segundo item da lista à 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 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 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 in
)
;;
[opção 2] )
;;
* )
< comandos se não for nenhuma das
opções >
;;
esac
Vamos as explicações. O Case pega a string fornecida em e compara com . Se forem iguais, ele executa e sai fora. Caso contrario, ele compara com e assim por diante.
Caso 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..."
;;
'restart' )
echo "Reinicializando o serviço..."
;;
'stop' )
echo "Parando 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 in ;
do
done;
Como disse acima, o select vai mostrar as opções contidas em , 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 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!
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 in ;
do
comandos
done;
O For associa o primeiro item da lista de nomes à variável e executa os comandos. Em seguida, associa novamente o segundo item da lista à 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 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 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 in
)
;;
[opção 2] )
;;
* )
< comandos se não for nenhuma das
opções >
;;
esac
Vamos as explicações. O Case pega a string fornecida em e compara com . Se forem iguais, ele executa e sai fora. Caso contrario, ele compara com e assim por diante.
Caso 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..."
;;
'restart' )
echo "Reinicializando o serviço..."
;;
'stop' )
echo "Parando 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 in ;
do
done;
Como disse acima, o select vai mostrar as opções contidas em , 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 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!