O awk é uma ferramenta poderosa para processamento de texto em shell script. Nesta aula, vamos aprofundar o uso de variáveis, estruturas de controle (condicionais e loops) e os blocos especiais BEGIN e END, que permitem executar ações antes e depois do processamento principal. Ao final, você será capaz de gerar relatórios complexos diretamente da linha de comando ou em scripts.

Dominar esses conceitos é essencial para automatizar análises de logs, extrair dados de arquivos CSV e criar resumos estatísticos. Vamos começar!

Variáveis e operações

No awk, variáveis podem ser definidas pelo usuário ou herdadas do shell. Elas não precisam ser declaradas e seu tipo é inferido dinamicamente. Variáveis numéricas são inicializadas com zero, e strings com vazio. Você pode usar variáveis para armazenar contagens, somas, valores de campo e resultados intermediários.

Operações aritméticas como +, -, *, / e % funcionam normalmente. Para strings, a concatenação é feita justapondo-as. Exemplo: total = total + $1 ou nome = $1 " " $2. Também é possível usar operadores de atribuição como +=, -=, etc.

# Exemplo: somar o primeiro campo de cada linha
awk '{ soma += $1 } END { print "Soma:", soma }' dados.txt

# Usando variável definida pelo usuário
awk -v fator=2 '{ print $1 * fator }' dados.txt

Condicionais e loops

O awk suporta as estruturas condicionais if, if-else e if-else if-else, além de operadores lógicos (&&, ||, !). A sintaxe é similar ao C. Os comandos podem ser agrupados com chaves. Exemplo: if ($1 > 10) { print $1 } else { print "menor" }.

Os loops disponíveis são while, do-while e for. O for pode ser usado tanto no estilo C (for (i=1; i<=NF; i++)) quanto para percorrer arrays (for (i in array)). Os comandos break e continue funcionam como esperado.

# Usando if para filtrar linhas
awk '{ if ($3 > 100) print $0 }' vendas.txt

# Loop for para somar todos os campos de cada linha
awk '{ soma=0; for(i=1; i<=NF; i++) soma+=$i; print soma }' dados.txt

BEGIN e END

Os blocos BEGIN e END são especiais: o BEGIN é executado antes de qualquer linha ser lida, ideal para inicializar variáveis, imprimir cabeçalhos ou configurar separadores. O END é executado após o processamento de todas as linhas, usado para resumos, totais e relatórios finais.

Você pode ter múltiplos blocos BEGIN e END, e eles serão executados na ordem em que aparecem. É comum usar BEGIN para definir o separador de campo com FS ou OFS. Exemplo: BEGIN { FS=","; OFS="|" }.

# Exemplo com BEGIN e END
awk 'BEGIN { print "Início do processamento" }
     { total += $1 }
     END { print "Total:", total }' numeros.txt

# Configurando separador no BEGIN
awk 'BEGIN { FS=":"; OFS="-" } { print $1, $3 }' /etc/passwd

Relatórios

Combinando os recursos anteriores, podemos gerar relatórios formatados. O awk permite formatar saída com printf, similar ao C, controlando largura de campos, alinhamento e casas decimais. Você pode criar tabelas, resumos estatísticos e até gráficos simples com caracteres.

Um relatório típico pode incluir cabeçalho (no BEGIN), processamento linha a linha com acumulação de dados, e rodapé com totais (no END). Use arrays associativos para agrupar dados por chave, como por departamento ou mês.

# Relatório de vendas por vendedor
awk 'BEGIN { printf "%-15s %10s\n", "Vendedor", "Total"
            printf "%s\n", "-------------------------" }
     { vendas[$1] += $2 }
     END { for (v in vendas) printf "%-15s %10.2f\n", v, vendas[v] }' vendas.csv

Boas práticas

Use -v para passar variáveis do shell para o awk, evitando problemas com aspas. Comente blocos complexos. Prefira printf para formatação precisa. Teste com pequenos conjuntos de dados antes de processar arquivos grandes.

Referências

Exercícios

  1. Escreva um comando awk que some todos os números do primeiro campo de um arquivo, ignorando linhas que começam com #.
  2. ✓ Resposta:
    awk '!/^#/ { soma += $1 } END { print soma }' arquivo.txt
  3. Crie um relatório que exiba, para cada mês (campo 2 no formato "2024-01"), o total do campo 3. Use arrays associativos.
  4. ✓ Resposta:
    awk '{ total[$2] += $3 } END { for (mes in total) print mes, total[mes] }' dados.csv
  5. Use o bloco BEGIN para definir o separador de campo como vírgula e imprimir um cabeçalho "Nome,Idade".
  6. ✓ Resposta:
    awk 'BEGIN { FS=","; print "Nome,Idade" } { print $1 "," $2 }' pessoas.csv
  7. Escreva um comando awk que use um loop para imprimir cada campo de uma linha em linhas separadas.
  8. ✓ Resposta:
    awk '{ for(i=1; i<=NF; i++) print $i }' arquivo.txt
  9. Gere um relatório que mostre a média do campo 2 para cada valor único do campo 1.
  10. ✓ Resposta:
    awk '{ soma[$1] += $2; cont[$1]++ } END { for (k in soma) print k, soma[k]/cont[k] }' dados.txt