Laço for no Bash
LidoNesta aula, você aprenderá a usar o laço for no Bash, explorando desde a iteração sobre listas até o estilo C-style, além de entender como o globbing facilita o trabalho com arquivos. Com exemplos práticos, você dominará essa estrutura essencial para automatizar tarefas no shell.
O laço for é uma das estruturas de repetição mais utilizadas em scripts Bash, pois permite executar um conjunto de comandos para cada item de uma lista. Diferente de linguagens como C ou Python, o Bash oferece múltiplas sintaxes para o for, cada uma adequada a diferentes cenários, como iterar sobre argumentos, arquivos que correspondem a um padrão, ou até mesmo simular um contador numérico.
Nesta aula, vamos explorar as principais formas de usar o for: sobre listas explícitas, sobre arquivos via globbing, e a versão estilo C, que é útil para loops numéricos. Ao final, você terá uma compreensão sólida para aplicar em seus próprios scripts.
Sobre listas
No Bash, um laço for pode percorrer uma lista de palavras ou strings. A sintaxe básica é:
for variável in lista; do
comandos
doneA lista pode ser definida de várias formas: diretamente na linha de comando, através de uma variável, ou por expansão de comandos. Por exemplo, podemos iterar sobre números ou nomes:
#!/bin/bash
# Iterando sobre uma lista literal
for fruta in maçã banana laranja; do
echo "Fruta: $fruta"
done
# Usando uma variável
lista="um dois três"
for item in $lista; do
echo "Item: $item"
done
# Gerando lista com comando
for arquivo in $(ls); do
echo "Arquivo: $arquivo"
doneÉ importante notar que, se a lista contiver espaços em branco dentro de um item, será necessário usar aspas ou escapar, pois o Bash divide a lista por espaços. Para listas mais complexas, pode-se usar arrays:
#!/bin/bash
# Array de frutas
frutas=("maçã" "banana" "laranja")
for fruta in "${frutas[@]}"; do
echo "Fruta: $fruta"
doneOutra forma comum é iterar sobre uma sequência de números com o comando seq ou a expansão {início..fim}:
#!/bin/bash
# Usando expansão de chaves
for i in {1..5}; do
echo "Número: $i"
done
# Usando comando seq
for i in $(seq 1 2 10); do
echo "Número (incremento 2): $i"
doneO laço for também pode percorrer os argumentos de linha de comando usando "$@", o que é útil para scripts que aceitam parâmetros:
#!/bin/bash
for arg in "$@"; do
echo "Argumento: $arg"
doneSobre arquivos (globbing)
O globbing é um recurso do shell que expande padrões de arquivos, como *.txt, em uma lista de nomes de arquivos correspondentes. Isso é extremamente útil com o laço for para processar vários arquivos de uma só vez.
Por exemplo, para renomear todos os arquivos .txt para .bak, podemos fazer:
#!/bin/bash
for arquivo in *.txt; do
mv "$arquivo" "${arquivo%.txt}.bak"
doneAtenção: se não houver nenhum arquivo correspondente ao padrão, o glob permanece literal (a menos que a opção nullglob esteja ativada). Para evitar erros, é comum verificar se o arquivo existe:
#!/bin/bash
for arquivo in *.txt; do
if [ -e "$arquivo" ]; then
echo "Processando $arquivo"
else
echo "Nenhum arquivo .txt encontrado"
fi
doneTambém é possível usar padrões mais complexos, como *.log, data?.txt, ou combinar múltiplos padrões:
#!/bin/bash
# Processar arquivos .jpg e .png
for imagem in *.jpg *.png; do
echo "Imagem: $imagem"
doneO globbing também funciona com caminhos, como ./subdir/*.conf, e pode ser usado para iterar sobre todos os arquivos de um diretório, incluindo subdiretórios, usando o globstar (se ativado com shopt -s globstar):
#!/bin/bash
shopt -s globstar
for arquivo in **/*.sh; do
echo "Script: $arquivo"
doneÉ fundamental citar as variáveis com aspas duplas para evitar que o shell interprete caracteres especiais contidos nos nomes dos arquivos.
for C-style
O Bash também suporta uma sintaxe de for inspirada na linguagem C, que é útil para loops numéricos com controle de incremento. A sintaxe é:
for (( inicialização; condição; incremento )); do
comandos
donePor exemplo, para imprimir números de 1 a 10:
#!/bin/bash
for (( i=1; i<=10; i++ )); do
echo "Número: $i"
doneEssa forma permite expressões aritméticas completas, como decremento, incremento de mais de um, ou condições complexas:
#!/bin/bash
# Decrecente de 10 a 1
for (( i=10; i>0; i-- )); do
echo "Contagem regressiva: $i"
done
# Incremento de 2
for (( i=0; i<=20; i+=2 )); do
echo "Par: $i"
done
# Condição composta
for (( i=1, j=10; i<=j; i++, j-- )); do
echo "i=$i, j=$j"
doneEsse estilo é particularmente útil quando você precisa de um controle fino sobre o índice, como em operações com arrays por índice:
#!/bin/bash
frutas=("maçã" "banana" "laranja")
for (( i=0; i<${#frutas[@]}; i++ )); do
echo "Fruta $((i+1)): ${frutas[$i]}"
donePerceba que as variáveis de controle são inteiras, e as expressões são avaliadas no contexto aritmético do Bash.
Exemplos
Vamos consolidar com alguns exemplos práticos que combinam as diferentes formas do laço for:
Exemplo 1: Backup de arquivos com data
#!/bin/bash
# Cria backup de todos os .conf em um diretório com timestamp
backup_dir="backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$backup_dir"
for arquivo in *.conf; do
if [ -e "$arquivo" ]; then
cp "$arquivo" "$backup_dir/"
echo "Copiado $arquivo"
fi
doneExemplo 2: Somatório com C-style
#!/bin/bash
# Calcula a soma de 1 a 100
soma=0
for (( i=1; i<=100; i++ )); do
soma=$((soma + i))
done
echo "Soma: $soma"Exemplo 3: Processar argumentos com validação
#!/bin/bash
# Exibe os argumentos que são arquivos regulares
for arg in "$@"; do
if [ -f "$arg" ]; then
echo "$arg é um arquivo regular."
elif [ -d "$arg" ]; then
echo "$arg é um diretório."
else
echo "$arg não é um arquivo ou diretório."
fi
doneExemplo 4: Iteração sobre linhas de um arquivo
Embora o while read seja mais adequado para ler linhas, o for pode ser usado com o comando cat, mas cuidado com espaços:
#!/bin/bash
# Lê palavras de um arquivo (quebra por espaços)
for palavra in $(cat arquivo.txt); do
echo "Palavra: $palavra"
doneSe o arquivo tiver linhas com espaços, prefira while.
Exemplo 5: Geração de relatório com múltiplos arquivos
#!/bin/bash
# Conta linhas de todos os scripts .sh no diretório atual
total=0
for script in *.sh; do
if [ -e "$script" ]; then
linhas=$(wc -l < "$script")
echo "$script: $linhas linhas"
total=$((total + linhas))
fi
done
echo "Total de linhas: $total"Esses exemplos mostram a versatilidade do laço for no Bash. Lembre-se de sempre testar seus scripts com entradas variadas para garantir robustez.
Boas práticas e observações finais
- Sempre use aspas duplas em variáveis que podem conter espaços ou caracteres especiais, especialmente em nomes de arquivos.
- Prefira
forcom globbing para arquivos, mas verifique se o padrão não é literal (usenullglobse necessário). - Para loops numéricos, o estilo C-style é mais legível e eficiente do que usar
seq. - Evite usar
forpara ler linhas de arquivos; utilizewhile readpara preservar espaços e caracteres especiais. - Teste seus scripts com
bash -xpara depurar o comportamento do laço.
Exercícios
Escreva um script que use um laço
forpara imprimir os números de 1 a 20, mas apenas os pares.✓ Resposta:#!/bin/bash for (( i=1; i<=20; i++ )); do if (( i % 2 == 0 )); then echo $i fi doneCrie um script que renomeie todos os arquivos com extensão
.txtno diretório atual para.bak, usando globbing.✓ Resposta:#!/bin/bash for arquivo in *.txt; do if [ -e "$arquivo" ]; then mv "$arquivo" "${arquivo%.txt}.bak" fi doneEscreva um script que some todos os argumentos passados na linha de comando (suponha que sejam números).
✓ Resposta:#!/bin/bash soma=0 for num in "$@"; do soma=$((soma + num)) done echo "Soma: $soma"Utilizando o estilo C-style, crie um script que imprima uma contagem regressiva de 10 a 1, e depois a mensagem "Lançar!".
✓ Resposta:#!/bin/bash for (( i=10; i>0; i-- )); do echo $i done echo "Lançar!"Escreva um script que liste todos os arquivos .log no diretório atual e, para cada um, exiba seu tamanho em bytes usando o comando
stat.✓ Resposta:#!/bin/bash for arquivo in *.log; do if [ -e "$arquivo" ]; then tamanho=$(stat -c %s "$arquivo") echo "$arquivo: $tamanho bytes" fi done