Loops: for, while e until

1. Introdução aos Loops em Bash

1.1. Por que usar loops em scripts?

Loops são estruturas fundamentais em qualquer linguagem de programação, e no Bash não é diferente. Eles permitem automatizar tarefas repetitivas, processar listas de arquivos, ler arquivos linha por linha, e executar comandos enquanto uma condição for verdadeira ou falsa. Sem loops, scripts se tornariam longos, repetitivos e propensos a erros.

1.2. Diferenças fundamentais entre for, while e until

  • for: Itera sobre uma lista predefinida de itens (palavras, números, arquivos) ou segue uma sequência numérica controlada. Ideal quando você sabe exatamente quantas iterações serão necessárias.
  • while: Executa enquanto uma condição for verdadeira. Útil para situações onde o número de iterações é indeterminado, como ler um arquivo até o final ou aguardar um evento.
  • until: Funciona de forma oposta ao while: executa enquanto a condição for falsa, parando quando ela se torna verdadeira. Excelente para esperar que algo aconteça.

1.3. Sintaxe básica de cada tipo de loop

# for - iteração sobre lista
for variavel in lista; do
    comandos
done

# while - executa enquanto condição for verdadeira
while condicao; do
    comandos
done

# until - executa até condição se tornar verdadeira
until condicao; do
    comandos
done

2. Loop for: Iteração sobre listas e sequências

2.1. Estrutura clássica: for var in lista; do ... done

O for clássico percorre uma lista de palavras separadas por espaço:

#!/bin/bash
# Listando diretórios dentro de /home
for usuario in /home/*; do
    if [ -d "$usuario" ]; then
        echo "Diretório: $(basename $usuario)"
    fi
done

2.2. Gerando sequências com {inicio..fim..passo} e seq

O Bash oferece expansão de chaves para criar sequências de forma elegante:

#!/bin/bash
# Números ímpares de 1 a 10
for i in {1..10..2}; do
    echo "Ímpar: $i"
done

# Usando seq (mais portável)
for i in $(seq 1 2 10); do
    echo "Ímpar (seq): $i"
done

2.3. Uso do for estilo C: for (( i=0; i<10; i++ ))

Para maior controle sobre índices e condições complexas, use a sintaxe estilo C:

#!/bin/bash
# Tabuada do 5
for (( i=1; i<=10; i++ )); do
    echo "5 x $i = $((5 * i))"
done

3. Loop while: Execução condicional contínua

3.1. Sintaxe e funcionamento: executa enquanto condição for verdadeira

O while verifica a condição antes de cada iteração. Enquanto o comando de condição retornar código de saída 0 (sucesso), o loop continua:

#!/bin/bash
# Contagem regressiva
contador=10
while [ $contador -gt 0 ]; do
    echo "Faltam $contador segundos..."
    ((contador--))
    sleep 1
done
echo "Tempo esgotado!"

3.2. Leitura de arquivos linha a linha com while read

Uma das aplicações mais comuns do while é processar arquivos linha por linha:

#!/bin/bash
# Lendo um arquivo CSV simples
while IFS=',' read -r nome idade cidade; do
    echo "Nome: $nome | Idade: $idade | Cidade: $cidade"
done < "dados.txt"

3.3. Loops infinitos e controle com break e continue

Loops infinitos são úteis para serviços ou monitores:

#!/bin/bash
# Loop infinito com condição de saída
while true; do
    echo "Verificando conexão..."
    if ping -c 1 google.com &> /dev/null; then
        echo "Conectado!"
        break
    fi
    sleep 5
done

4. Loop until: O inverso do while

4.1. Sintaxe e lógica: executa até que a condição se torne verdadeira

O until repete o bloco enquanto a condição for falsa (retorno diferente de 0):

#!/bin/bash
# Aguarda até que o usuário digite "sair"
resposta=""
until [ "$resposta" = "sair" ]; do
    read -p "Digite 'sair' para encerrar: " resposta
    echo "Você digitou: $resposta"
done

4.2. Comparação prática entre while e until

#!/bin/bash
# Mesmo comportamento com while e until
echo "Usando while:"
contador=0
while [ $contador -lt 5 ]; do
    echo $contador
    ((contador++))
done

echo "Usando until:"
contador=0
until [ $contador -ge 5 ]; do
    echo $contador
    ((contador++))
done

4.3. Exemplo: aguardar um arquivo ser criado

#!/bin/bash
# Monitora até o arquivo aparecer
ARQUIVO="/tmp/processo_concluido.txt"
until [ -f "$ARQUIVO" ]; do
    echo "Aguardando $ARQUIVO ser criado..."
    sleep 2
done
echo "Arquivo encontrado! Processo concluído."

5. Controle de Fluxo dentro de Loops

5.1. break: interromper o loop prematuramente

#!/bin/bash
# Encontra o primeiro número divisível por 7 entre 1 e 100
for num in {1..100}; do
    if (( num % 7 == 0 )); then
        echo "Primeiro múltiplo de 7: $num"
        break
    fi
done

5.2. continue: pular para a próxima iteração

#!/bin/bash
# Exibe apenas números pares
for i in {1..10}; do
    if (( i % 2 != 0 )); then
        continue
    fi
    echo "Par: $i"
done

5.3. Uso combinado com condicionais (if, case)

#!/bin/bash
# Processa comandos com case dentro de while
while true; do
    read -p "Comando (start/stop/status/sair): " cmd
    case $cmd in
        start)  echo "Iniciando serviço..." ;;
        stop)   echo "Parando serviço..." ;;
        status) echo "Serviço ativo." ;;
        sair)   echo "Encerrando."; break ;;
        *)      echo "Comando inválido." ;;
    esac
done

6. Loops Aninhados e Boas Práticas

6.1. Exemplo de loop dentro de outro loop

#!/bin/bash
# Tabela de multiplicação 3x3
for i in {1..3}; do
    for j in {1..3}; do
        printf "%3d" $((i * j))
    done
    echo
done

6.2. Cuidados com desempenho e legibilidade

  • Evite loops aninhados profundos (mais de 2 níveis) — eles são difíceis de entender e lentos.
  • Prefira while read a for ao processar arquivos grandes, pois for carrega tudo na memória.
  • Use (( )) para aritmética em vez de expr ou let.

6.3. Evitando armadilhas comuns

# ERRADO: variável não escapada
for arquivo in *.txt; do
    rm $arquivo  # Perigoso se arquivo tiver espaços
done

# CORRETO: sempre use aspas duplas
for arquivo in *.txt; do
    rm "$arquivo"
done

# Cuidado com subshells: while ... | read cria subshell
# ERRADO:
echo "linha1 linha2" | while read linha; do
    echo "$linha"
done
# 'linha' não existe fora do while

# CORRETO: redirecionamento sem pipe
while read linha; do
    echo "$linha"
done < <(echo "linha1 linha2")

7. Exemplos Práticos e Casos de Uso

7.1. Renomear arquivos em lote com for

#!/bin/bash
# Adiciona prefixo "backup_" a todos os .txt
for arquivo in *.txt; do
    mv "$arquivo" "backup_$arquivo"
done
echo "Arquivos renomeados."

7.2. Monitorar log até encontrar padrão com until

#!/bin/bash
# Monitora /var/log/syslog até aparecer "ERROR"
LOG="/var/log/syslog"
until grep -q "ERROR" "$LOG" 2>/dev/null; do
    echo "Monitorando $LOG... (CTRL+C para sair)"
    sleep 3
done
echo "Erro encontrado no log!"

7.3. Menu interativo com while verdadeiro e case

#!/bin/bash
while true; do
    echo "===== MENU ====="
    echo "1) Listar diretório"
    echo "2) Mostrar data"
    echo "3) Sair"
    read -p "Escolha: " opcao
    case $opcao in
        1) ls -la ;;
        2) date ;;
        3) echo "Até logo!"; break ;;
        *) echo "Opção inválida" ;;
    esac
    echo
done

Referências