Como usar grep, awk e sed juntos para processar logs

O processamento de logs é uma tarefa essencial para administradores de sistemas, desenvolvedores e profissionais de segurança. Três ferramentas clássicas do Unix/Linux — grep, awk e sed — formam uma tríade poderosa quando combinadas em pipelines. Este artigo explora como usar essas ferramentas em conjunto para extrair, transformar e analisar logs de forma eficiente, seguindo a metodologia da Lista Final de 1200 temas.

1. Fundamentos da Tríade: grep, awk e sed no Contexto de Logs

1.1. Papéis Complementares

Cada ferramenta tem uma função específica no pipeline de processamento:

  • grep: Filtra linhas que correspondem a padrões. É a primeira linha de defesa para reduzir o volume de dados.
  • sed: Transforma linhas individualmente. Ideal para substituições, remoções e formatação.
  • awk: Analisa dados estruturados por campos. Excelente para cálculos, agregações e relatórios.

1.2. Padrão de Pipeline

O encadeamento com pipes (|) permite que a saída de uma ferramenta seja entrada da próxima:

grep "ERRO" arquivo.log | sed 's/old/new/g' | awk '{print $1, $5}'

1.3. Diferenças de Performance

  • grep: Mais rápido para busca linear. Use para filtrar grandes volumes.
  • sed: Eficiente para transformações em streaming. Processa linha por linha.
  • awk: Mais lento, mas oferece maior poder de análise. Use após reduzir o volume com grep.

2. Filtrando Logs com grep: Primeira Etapa do Pipeline

2.1. Expressões Regulares para Isolar Eventos

# Isolar erros críticos
grep -E "CRITICAL|FATAL" /var/log/syslog

# Filtrar por data específica
grep "2024-03-15" /var/log/apache2/access.log

2.2. Flags Essenciais

# Contar ocorrências
grep -c "ERROR" app.log

# Contexto ao redor do padrão
grep -A 2 -B 1 "Timeout" server.log

# Inverter seleção (excluir linhas)
grep -v "DEBUG" application.log

2.3. Combinando Múltiplos Padrões

# Usando egrep (ou grep -E)
egrep "401|403|500" access.log

# Pipes aninhados
grep "ERROR" log.txt | grep -v "TIMEOUT" | grep "2024"

3. Transformando Linhas com sed: Limpeza e Formatação

3.1. Substituições Básicas

# Normalizar timestamps
sed 's/Jan/01/g; s/Feb/02/g' syslog.txt

# Mascarar IPs
sed 's/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/XXX.XXX.XXX.XXX/g' access.log

3.2. Comandos de Linha

# Deletar linhas de debug
sed '/^DEBUG/d' application.log

# Extrair intervalo entre marcadores
sed -n '/START/,/END/p' logfile.txt

3.3. Grupos de Captura para Reordenar Campos

# Reordenar data (YYYY-MM-DD para DD/MM/YYYY)
echo "2024-03-15 10:30:00 ERRO" | sed 's/\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\)/\3\/\2\/\1/'

4. Analisando Dados Estruturados com awk: Processamento por Campos

4.1. Separação de Campos

# Campos padrão (espaço como delimitador)
awk '{print $1, $3, $NF}' access.log

# Delimitador customizado
awk -F':' '{print $1, $2}' /etc/passwd

4.2. Blocos BEGIN/END e Condicionais

# Cabeçalho e sumário
awk 'BEGIN {print "IP\t\tCOUNT"} 
     /ERROR/ {count[$1]++} 
     END {for (ip in count) print ip, count[ip]}' server.log

4.3. Funções Internas

# Extrair substring
awk '{print substr($4, 2, 11)}' access.log

# Dividir campo
awk '{split($1, partes, "/"); print partes[1]}' log.txt

# Substituir dentro do awk
awk '{gsub(/erro/, "ERRO"); print}' log.txt

5. Pipeline Completo: grep + sed + awk em Cascata

5.1. Exemplo 1: Requisições HTTP 500 do Apache

# Extrair URLs com erro 500, limpar timestamp e agrupar
grep " 500 " /var/log/apache2/access.log |
sed 's/\[//g; s/\]//g' |
awk '{
    split($4, data, "/");
    url = $7;
    contagem[url]++
} 
END {
    for (url in contagem) 
        print contagem[url], url
}' | sort -rn | head -10

5.2. Exemplo 2: Erros de Autenticação

# Filtrar falhas de login, remover duplicatas, contar por usuário
grep "authentication failure" /var/log/auth.log |
sed 's/.*user=\([^ ]*\).*/\1/' |
awk '!seen[$0]++' |
awk '{usuarios[$1]++} 
     END {for (u in usuarios) print u, usuarios[u]}'

5.3. Exemplo 3: Falhas de Disco no Syslog

# Isolar falhas de disco, reformatar data/hora, gerar relatório
grep -E "I/O error|disk failure" /var/log/syslog |
sed 's/\([A-Z][a-z]\{2\}\) *\([0-9]\{2\}\) /\1 \2 /' |
awk '{
    split($1, data, " ");
    mes = data[1];
    dia = data[2];
    hora = $2;
    dispositivo = $NF;
    print dia "/" mes " " hora " - " dispositivo
}' | sort | uniq -c | sort -rn

6. Otimizações e Boas Práticas para Logs Grandes

6.1. Ordem das Operações

Sempre aplique grep primeiro para reduzir o volume de dados antes de processar com sed e awk:

# Ineficiente
cat arquivo.log | awk '{...}' | sed '{...}' | grep "padrao"

# Eficiente
grep "padrao" arquivo.log | sed '{...}' | awk '{...}'

6.2. Processamento Paralelo

# Com xargs para múltiplos arquivos
ls *.log | xargs -P 4 -I {} sh -c 'grep "ERROR" {} | awk "{print \$1}" > {}.out'

# Com GNU parallel
parallel 'grep "WARNING" {} | sed "s/old/new/g"' ::: *.log

6.3. Cuidados com Caracteres Especiais

# Aspas simples para evitar expansão de variáveis
awk '{print $1}' arquivo.log  # Correto

# Escapar caracteres especiais em regex
grep "erro\[0-9\]" arquivo.log  # Literal '[0-9]'

7. Integração com Outras Ferramentas do Ecossistema Linux

7.1. Análises Estatísticas com sort, uniq e head

# Top 10 IPs mais frequentes
grep " 200 " access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

7.2. Monitoramento em Tempo Real com tee

# Monitorar logs ao vivo enquanto salva
tail -f /var/log/syslog | grep "ERROR" | tee erros.log | awk '{print $1, $3, $NF}'

7.3. Pipeline Contínuo com journalctl

# Logs do systemd em tempo real
journalctl -f -u nginx.service | grep " 500 " | sed 's/.*\[\(.*\)\].*/\1/' | awk '{count[$1]++} END {for (k in count) print k, count[k]}'

Referências