O Bash tem duas formas de laço:
for
Para iterar sobre uma lista de itens, usamos o laço for.
for varname in words; do COMMANDS; done
words é expandido usando divisão de palavras e expansão de nomes de arquivos (que aprendemos no conceito Quoting).
Cada palavra é atribuída ao varname, uma por vez, e os COMMANDS são executados.
Aqui estão alguns exemplos que mostram quando o laço for pode ser útil
Executar alguns comandos em um grupo de arquivos.
# source all the bash library files in the current directory
for file in ./*.bash; do
source "$file"
done
Executar algum comando em cada um dos parâmetros de um script ou função.
for arg in "$@"; do
echo "argument: ${arg}"
done
Executar algum comando para cada palavra separada por espaço na saída de um comando.
for i in $(seq 10); do
echo "${i} squared is $((i * i))"
done
Vamos ver alguns avisos sobre esse estilo mais adiante.
for aritméticoO Bash tem sim um laço aritmético. Ele vai parecer um pouco familiar para quem conhece outras linguagens de programação.
for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done
Os parênteses duplos no Bash representam um contexto aritmético (veremos mais sobre a aritmética do Bash em um conceito posterior).
O exemplo acima que usa seq pode ser escrito assim
for ((i = 1; i <= 10; i++)); do
echo "${i} squared is $((i * i))"
done
for
Este é um antipadrão que você vai ver com frequência: iterar sobre a saída do cat.
for line in $(cat some.file); do
do_something_with "$line"
done
Isso está errado por dois motivos.
for está iterando sobre as palavras do arquivo, não sobre as linhas.Como aprendemos no conceito Quoting, a divisão de palavras pode ser controlada com a variável IFS, e a expansão de nomes de arquivos pode ser desativada.
Mas essa costuma ser uma solução frágil.
O for é o método errado para iterar sobre as linhas de um arquivo.
A forma idiomática de ler um arquivo é com um laço while.
while
Use o while para repetir uma sequência de comandos enquanto uma condição for verdadeira.
while CONDITION_COMMANDS; do COMMANDS; done
Assim como no if (como aprendemos no conceito Condicionais, não há sintaxe especial para CONDITION_COMMANDS.
O status de saída da lista de comandos vai determinar "verdadeiro" ou "falso".
O comando break salta para fora do laço.
O controle continua com o comando que vem depois do terminador done do laço.
O comando continue salta para a próxima iteração do laço.
Como mencionado, um laço while é a forma idiomática de ler um arquivo.
while IFS= read -r line; do
do_something_with "$line"
done < some.file
O conteúdo do arquivo é fornecido como entrada para o laço com o redirecionamento <.
O comando read retorna "verdadeiro" se conseguir ler uma linha inteira da sua entrada.
Quando a entrada é consumida, ou se a última linha termina sem uma quebra de linha no final, o read retorna "falso".
A forma realmente idiomática de ler as linhas de um arquivo, mesmo que a última linha não termine com uma quebra de linha, é
while IFS= read -r line || [[ -n "$line" ]]; do ...
A opção -r diz ao read para não substituir sequências de barra invertida: uma barra invertida é apenas um caractere comum.
IFS= atribui a string vazia a IFS apenas durante a execução do comando read.
Isso desativa temporariamente a divisão de palavras para que qualquer espaço em branco no início ou no final da linha de texto recebida seja preservado.
A construção until repete uma sequência de comandos enquanto uma condição for falsa.
O laço se repete até que a condição se torne verdadeira.
until CONDITION_COMMANDS; do COMMANDS; done
É raro usar o until.
É mais comum usar um laço "while not".
while ! CONDITION_COMANDS; do ...
Às vezes você quer repetir para sempre. Aqui estão duas formas de fazer isso.
um laço while com uma condição que sempre tem um status de saída de sucesso
while true; do ...
um laço for aritmético com expressões vazias
for ((;;)); do ...
Não existe uma construção do-while explícita, mas você pode obter o mesmo efeito:
while true; do
COMMANDS
if END_CONDITION; then
break
fi
done