for com lista

A forma mais comum do for itera sobre uma lista de palavras:

for DISTRO in debian ubuntu fedora arch; do
  echo "Distro: $DISTRO"
done
Distro: debian
Distro: ubuntu
Distro: fedora
Distro: arch

Você pode usar expansão de chaves ou a saída de um comando:

# Sequência numérica
for i in {1..5}; do
  echo "Servidor srv-$i"
done

# Saída de comando
for USER in $(cut -d: -f1 /etc/passwd | head -3); do
  echo "Usuário: $USER"
done

for estilo C

Para iterações numéricas com controle fino, use a sintaxe for ((;;)):

for ((i=0; i<5; i++)); do
  echo "Passo $i"
done
Passo 0
Passo 1
Passo 2
Passo 3
Passo 4

while

O while executa enquanto a condição for verdadeira. Muito usado com read para processar arquivos linha a linha:

# Contar de 1 a 5
COUNT=1
while [[ $COUNT -le 5 ]]; do
  echo "Contagem: $COUNT"
  ((COUNT++))
done

while read — processando arquivos

A forma idiomática de ler um arquivo no Bash:

while IFS=: read -r USER _ UID_ _; do
  if [[ $UID_ -ge 1000 ]]; then
    echo "Usuário humano: $USER (UID $UID_)"
  fi
done < /etc/passwd
Usuário humano: joao (UID 1000)
Usuário humano: maria (UID 1001)
Dica: Use IFS=: antes de read para mudar o delimitador sem afetar o resto do script. O -r impede que barras invertidas sejam interpretadas.

until

O until é o inverso do while: executa até que a condição se torne verdadeira.

# Esperar um serviço subir
until systemctl is-active --quiet nginx; do
  echo "Aguardando nginx..."
  sleep 2
done
echo "nginx está ativo!"

break e continue

break sai do loop imediatamente. continue pula para a próxima iteração.

for FILE in /var/log/*.log; do
  # Pular arquivos vazios
  [[ ! -s "$FILE" ]] && continue

  LINES=$(wc -l < "$FILE")
  echo "$FILE: $LINES linhas"

  # Parar após encontrar um arquivo com mais de 10000 linhas
  [[ $LINES -gt 10000 ]] && break
done

Iterando sobre arquivos

Use glob patterns para iterar sobre arquivos de forma segura:

# Renomear todos os .txt para .bak
for FILE in /tmp/dados/*.txt; do
  [[ -e "$FILE" ]] || continue  # protege contra glob sem match
  mv "$FILE" "${FILE%.txt}.bak"
  echo "Renomeado: $FILE"
done
Dica: Nunca faça for FILE in $(ls *.txt). Use glob direto: for FILE in *.txt. O ls quebra com espaços e caracteres especiais em nomes de arquivos.