Estratégias Poderosas de Loop: Iterando Arquivos e Listas em Scripts Bash
Loops Bash são o motor da automação em scripting de shell. Se você precisa processar cada arquivo em um diretório, executar uma tarefa um número definido de vezes, ou ler dados de configuração linha por linha, os loops fornecem a estrutura necessária para lidar com operações repetitivas de forma eficiente.
Mestrar os dois construtos primários de loop do Bash — for e while — é essencial para escrever scripts robustos, escaláveis e inteligentes. Este guia explora a sintaxe fundamental, casos de uso práticos e melhores práticas para iterar sobre listas, arquivos, diretórios e gerar sequências para impulsionar seus fluxos de trabalho de automação.
O Loop for: Iterando Sobre Conjuntos Fixos
O loop for é ideal quando você conhece a coleção de itens que precisa processar com antecedência. Essa coleção pode ser uma lista explícita de valores, os resultados de um comando, ou um conjunto de arquivos encontrados via globbing.
1. Iterando Sobre Listas Padrão
O caso de uso mais comum envolve iterar sobre uma lista de itens separados por espaço.
Sintaxe
for VARIAVEL in LISTA_DE_ITENS; do
# Comandos usando $VARIAVEL
done
Exemplo: Processando uma Lista de Usuários
# Lista de usuários a serem processados
USUARIOS="alice bob charlie"
for usuario in $USUARIOS; do
echo "Verificando o diretório home de $usuario..."
if [ -d "/home/$usuario" ]; then
echo "$usuario está ativo."
else
echo "Aviso: Diretório home de $usuario ausente."
fi
done
2. Iteração Numérica Estilo C
Para tarefas que exigem contagem ou sequências numéricas específicas, o Bash suporta um loop for estilo C, frequentemente combinado com expansão de chaves ou o comando seq.
Sintaxe (Estilo C)
for (( INICIALIZACAO; CONDICAO; INCREMENTO )); do
# Comandos
done
Exemplo: Script de Contagem Regressiva
# Loop 5 vezes (i começa em 1, continua enquanto i for menor ou igual a 5)
for (( i=1; i<=5; i++ )); do
echo "Número da iteração: $i"
sleep 1
done
echo "Pronto!"
Alternativa: Usando Expansão de Chaves para Sequências Simples
A expansão de chaves é mais simples e rápida do que usar seq para gerar inteiros ou sequências contíguas.
# Gera números de 10 a 1
for num in {10..1}; do
echo "Contagem regressiva: $num"
done
3. Iterando Sobre Arquivos e Diretórios (Globbing)
Usar curingas (*) dentro do loop for permite processar arquivos que correspondem a um padrão específico, como todos os arquivos de log ou todos os scripts em um diretório.
Exemplo: Arquivando Arquivos de Log
É crucial citar a variável ("$arquivo") ao lidar com nomes de arquivos, especialmente aqueles que contêm espaços ou caracteres especiais.
DIRETORIO_ALVO="/var/log/aplicacao"
# Loop sobre todos os arquivos terminados em .log no diretório alvo
for arquivo_log in "$DIRETORIO_ALVO"/*.log; do
# Verifica se um arquivo realmente existe (evita executar sobre o nome literal "*.log" se nenhum arquivo corresponder)
if [ -f "$arquivo_log" ]; then
echo "Comprimindo $arquivo_log..."
gzip "$arquivo_log"
fi
done
O Loop while: Execução Baseada em Condição
O loop while continua executando um bloco de comandos enquanto uma condição especificada permanecer verdadeira. É comumente usado para ler fluxos de entrada, monitorar condições, ou lidar com tarefas onde o número de iterações é desconhecido.
1. Loop while Básico
Sintaxe
while CONDICAO; do
# Comandos
done
Exemplo: Esperando por um Recurso
Este loop usa o comando test ([ ]) para verificar se um diretório existe antes de prosseguir.
CAMINHO_RECURSO="/mnt/dados/compartilhamento"
while [ ! -d "$CAMINHO_RECURSO" ]; do
echo "Aguardando o recurso $CAMINHO_RECURSO ser montado..."
sleep 5
done
echo "Recurso está disponível. Iniciando backup."
2. O Padrão Robusto while read
A aplicação mais poderosa do loop while é ler o conteúdo de um arquivo ou fluxo de saída linha por linha. Este padrão é muito superior a usar um loop for na saída do cat, pois lida de forma confiável com espaços e caracteres especiais.
Melhor Prática: Lendo Linha por Linha
Para garantir a máxima robustez, utilizamos três componentes chave:
1. IFS=: Limpa o Separador de Campo Interno, garantindo que a linha inteira, incluindo espaços iniciais/finais, seja lida na variável.
2. read -r: A opção -r impede a interpretação de barra invertida (leitura bruta), o que é crítico para caminhos e strings complexas.
3. Redirecionamento de Entrada (<): Redireciona o conteúdo do arquivo para dentro do loop, garantindo que o loop seja executado no contexto do shell atual (evitando problemas de subshell).
# Arquivo contendo dados, um item por linha
ARQUIVO_CONFIG="/etc/app/servidores.txt"
while IFS= read -r nome_servidor; do
# Pula linhas vazias ou linhas comentadas
if [[ -z "$nome_servidor" || "$nome_servidor" =~ ^# ]]; then
continue
fi
echo "Pinging servidor: $nome_servidor"
ping -c 1 "$nome_servidor"
done < "$ARQUIVO_CONFIG"
Dica: Evitando
catem LoopsNunca use
cat arquivo | while read linha; do...ao ler arquivos. O pipe cria um subshell, o que significa que variáveis definidas dentro do loop são perdidas quando o loop termina. Use o padrão de redirecionamento de entrada (while ... done < arquivo) em vez disso.
Controle e Técnicas Avançadas de Loop
Scripts eficazes exigem a capacidade de controlar a execução do loop com base em condições de tempo de execução.
1. Controle de Fluxo: break e continue
break: Sai imediatamente do loop inteiro, independentemente das iterações ou condições restantes.continue: Pula a iteração atual e vai imediatamente para a próxima iteração (ou reavalia a condiçãowhile).
Exemplo: Procurar e Parar
ALVO_PESQUISA="target.conf"
for arquivo in /etc/*; do
if [ -f "$arquivo" ] && [[ "$arquivo" == *"$ALVO_PESQUISA"* ]]; then
echo "Configuração alvo encontrada em: $arquivo"
break # Para o processamento assim que encontrado
elif [ -d "$arquivo" ]; then
continue # Pula diretórios, verifica apenas arquivos
fi
echo "Verificando arquivo: $arquivo"
done
2. Lidando com Delimitadores Complexos usando IFS
Enquanto a leitura de arquivos linha por linha exige a limpeza do IFS, a iteração sobre uma lista separada por um caractere diferente (como uma vírgula) requer a configuração temporária do IFS.
DADOS_CSV="data1,data2,data3,data4"
IFS_ANTIGO=$IFS # Salva o IFS original
IFS=',' # Define IFS para o caractere vírgula
for item in $DADOS_CSV; do
echo "Item encontrado: $item"
done
IFS=$IFS_ANTIGO # Restaura o IFS original imediatamente após o loop
Aviso: Alterações Globais de
IFSSempre salve o
$IFSoriginal antes de modificá-lo dentro de um script (por exemplo,IFS_ANTIGO=$IFS). Falhar em restaurar o valor original pode causar comportamento imprevisível em comandos subsequentes.
Melhores Práticas para Loops Robustos em Bash
| Prática | Justificativa |
|---|---|
| Sempre Cite Variáveis | Use "$variavel" para prevenir divisão de palavras e expansão de glob, especialmente na iteração de arquivos. |
Use while IFS= read -r |
O método mais confiável para processar arquivos linha por linha, lidando corretamente com espaços e caracteres especiais. |
| Verifique a Existência | Ao usar globbing (*.txt), sempre inclua uma verificação (if [ -f "$arquivo" ];) para garantir que o loop não processe o nome literal do padrão se nenhum arquivo corresponder. |
| Localize Variáveis | Use a palavra-chave local dentro de funções para evitar que variáveis de loop substituam acidentalmente variáveis globais. |
| Use Built-ins em Vez de Comandos Externos | Use expansão de chaves ({1..10}) ou loops estilo C em vez de invocar comandos externos como seq para obter desempenho. |
Conclusão
Loops for e while são fundamentais para o scripting Bash, permitindo tarefas de automação complexas com repetição mínima de código. Ao aplicar consistentemente padrões robustos — como a abordagem while IFS= read -r para processamento de arquivos e citação diligente em loops for — você pode construir scripts que são confiáveis, de alto desempenho e resistentes a formatos de dados inesperados, trazendo poder real para seus esforços de automação de shell.