Laços while e until
Esta aula aborda os laços while e until em shell script, explicando sua sintaxe, uso com o comando read para processar arquivos, e os comandos break e continue para controle de fluxo. São fornecidos exemplos práticos e exercícios para fixação.
Os laços de repetição são fundamentais em qualquer linguagem de programação, e no shell script não é diferente. Nesta aula, vamos explorar dois tipos de laços: while e until. Enquanto o while executa um bloco de comandos enquanto uma condição for verdadeira, o until faz o oposto: executa até que a condição se torne verdadeira. Além disso, veremos como usar o comando read dentro de um laço while para ler arquivos linha a linha, e como controlar a execução com break e continue.
while
O laço while repete um conjunto de comandos enquanto uma condição for verdadeira (retorno zero). Sua sintaxe é:
while condição; do
comandos
done
A condição pode ser qualquer comando ou teste. O laço termina quando o comando retorna um código diferente de zero. Exemplo simples que conta de 1 a 5:
#!/bin/bash
contador=1
while [ $contador -le 5 ]; do
echo "Contador: $contador"
((contador++))
done
Saída:
Contador: 1
Contador: 2
Contador: 3
Contador: 4
Contador: 5
Note o uso de ((contador++)) para incrementar a variável. Isso é uma expansão aritmética do Bash.
until
O laço until é semelhante ao while, mas executa os comandos enquanto a condição for falsa (retorno diferente de zero). Ele para quando a condição se torna verdadeira. Sintaxe:
until condição; do
comandos
done
Exemplo equivalente ao anterior, mas usando until:
#!/bin/bash
contador=1
until [ $contador -gt 5 ]; do
echo "Contador: $contador"
((contador++))
done
A condição é [ $contador -gt 5 ], que verifica se o contador é maior que 5. Enquanto isso for falso (contador menor ou igual a 5), o laço continua. Quando contador chega a 6, a condição é verdadeira e o laço termina.
read em while (lendo arquivos)
Uma aplicação muito comum do while é ler arquivos linha a linha usando o comando read. A estrutura típica é:
while IFS= read -r linha; do
echo "Linha: $linha"
done < arquivo.txt
O IFS= evita que espaços em branco no início ou fim da linha sejam removidos. A opção -r impede que barras invertidas sejam interpretadas como escapes. O redirecionamento < arquivo.txt fornece o conteúdo do arquivo como entrada para o laço.
Exemplo prático: criar um arquivo nomes.txt com um nome por linha e depois lê-lo:
#!/bin/bash
while IFS= read -r nome; do
echo "Olá, $nome!"
done < nomes.txt
Se nomes.txt contiver:
Ana
Bruno
Carla
A saída será:
Olá, Ana!
Olá, Bruno!
Olá, Carla!
break e continue
Os comandos break e continue permitem controlar o fluxo dentro de laços. break encerra o laço imediatamente, enquanto continue pula para a próxima iteração (ignorando os comandos restantes no corpo do laço).
Exemplo com break:
#!/bin/bash
for i in {1..10}; do
if [ $i -eq 5 ]; then
break
fi
echo "Número: $i"
done
Saída:
Número: 1
Número: 2
Número: 3
Número: 4
Exemplo com continue (pula o número 3):
#!/bin/bash
for i in {1..5}; do
if [ $i -eq 3 ]; then
continue
fi
echo "Número: $i"
done
Saída:
Número: 1
Número: 2
Número: 4
Número: 5
Em laços aninhados, você pode passar um número para break ou continue para indicar quantos níveis devem ser afetados (ex.: break 2 sai de dois laços).
Boas práticas
- Sempre use
IFS=e-rao ler arquivos comreadpara preservar o conteúdo original. - Evite laços infinitos acidentais: certifique-se de que a condição eventualmente se torna falsa (ou use
break). - Para loops baseados em números, prefira
forcom faixas ({1..10}) ou expressões aritméticas (((i++))). - Use
while truepara laços infinitos intencionais, mas sempre com uma rota de saída (ex.:break).
Referências
- GNU Bash Manual: Looping Constructs
- Advanced Bash-Scripting Guide: Loops
- Linuxize: Bash While Loop
- ShellCheck: Static analysis for shell scripts
- Greg's Wiki: How to read a file line by line?
Exercícios
- Escreva um script que use um laço
whilepara imprimir os números pares de 2 a 10. - Reescreva o exercício anterior usando
until. - Crie um script que leia o arquivo
/etc/passwdlinha a linha e exiba apenas os nomes de usuário (primeiro campo, separado por:). Dica: usecutou manipulação de string. - Escreva um script que use
while truepara exibir um menu com opções (1: Data, 2: Hora, 3: Sair). Usebreakpara sair quando o usuário escolher 3. - Modifique o script do exercício 4 para que, ao invés de
break, usecontinuepara exibir uma mensagem de "Opção inválida" e voltar ao menu, mas sem usarcase(useif).
#!/bin/bash
num=2
while [ $num -le 10 ]; do
echo $num
((num+=2))
done
#!/bin/bash
num=2
until [ $num -gt 10 ]; do
echo $num
((num+=2))
done
#!/bin/bash
while IFS=: read -r username _; do
echo "$username"
done < /etc/passwd
O IFS=: define o separador como dois pontos, e read atribui o primeiro campo a username e o resto a _ (descartado).
#!/bin/bash
while true; do
echo "1 - Data"
echo "2 - Hora"
echo "3 - Sair"
read -p "Escolha uma opção: " opcao
case $opcao in
1) date +%d/%m/%Y ;;
2) date +%H:%M:%S ;;
3) break ;;
*) echo "Opção inválida" ;;
esac
done
#!/bin/bash
while true; do
echo "1 - Data"
echo "2 - Hora"
echo "3 - Sair"
read -p "Escolha uma opção: " opcao
if [ "$opcao" -eq 1 ]; then
date +%d/%m/%Y
elif [ "$opcao" -eq 2 ]; then
date +%H:%M:%S
elif [ "$opcao" -eq 3 ]; then
break
else
echo "Opção inválida"
continue
fi
done
Note que o continue aqui é redundante, mas ilustra seu uso. Sem ele, o comportamento seria o mesmo, pois o laço volta ao início naturalmente.