Pipes no Linux: cut, sort, uniq e wc para analisar logs

Terminal Linux a mostrar um pipeline com cut, sort e uniq a contar os IPs mais frequentes de um access log

Há um momento em que qualquer administrador de sistemas ou analista de segurança se encontra sozinho com um ficheiro de log de milhares de linhas e uma pergunta urgente: quem está a fazer isto ao meu servidor? Não é preciso uma plataforma de análise, nem sequer sair do terminal. Com meia dúzia de utilitários minúsculos — cut, sort, uniq, wc, tr — ligados por pipes, o log em bruto transforma-se numa resposta em segundos.

Este artigo explica como funciona o operador |, percorre as opções que realmente interessam em cada um destes comandos e mostra o pipeline clássico da resposta a incidentes: o «top de IPs» de um access log. No fim, há um simulador interativo onde pode montar o funil, estágio a estágio, e ver o output intermédio de cada fase.

O que faz um pipeline

O pipe (|) liga a saída padrão de um comando à entrada padrão do seguinte. Cada programa faz uma única coisa bem feita — extrair um campo, ordenar, remover duplicados, contar — e o pipe encadeia-os num funil onde os dados fluem da esquerda para a direita. É a filosofia Unix em ação: em vez de uma ferramenta gigante que faz tudo, várias ferramentas pequenas que se combinam.

comando1 [ficheiro] | comando2 | comando3 > resultado.txt

O primeiro comando lê de um ficheiro (ou do teclado); os seguintes recebem sempre o que o anterior produziu. Um detalhe importante: alguns utilitários, como o tr, não aceitam ficheiros como argumento — leem apenas da entrada padrão, pelo que se usa o redirecionamento tr -s ' ' < ficheiro ou um comando antes deles no pipeline.

As opções que interessam

cut — extrair campos

O cut corta cada linha em campos e devolve só os que interessam. As duas opções essenciais andam sempre juntas: -d define o separador (por omissão é a tabulação) e -f escolhe os campos.

  • -d' ' -f1 — separa pelo espaço e fica com o primeiro campo. Num access log, é o IP do cliente.
  • -f1,3 e -f2-4 — aceita listas e intervalos de campos.
  • -c 1-15 — corta por posição de carácter em vez de campo.
  • --complement — inverte a seleção: devolve tudo menos os campos indicados.
  • -s — suprime as linhas que não contêm o separador (por omissão passam inteiras).

Uma armadilha clássica: o cut trata cada separador como uma fronteira de campo. Dois espaços seguidos criam um campo vazio e desviam todos os seguintes. Para dados irregulares, normalize primeiro com tr -s ' ' ou prefira awk, que trata sequências de espaços como um único separador.

sort — ordenar (e porquê antes do uniq)

  • sort — ordena as linhas como texto. É o passo obrigatório antes do uniq, porque este só agrega linhas repetidas consecutivas.
  • -n — compara como números. Sem ele, 10 vem antes de 9, porque «1» é menor do que «9» como carácter.
  • -r — inverte a ordem; -rn é o remate clássico de qualquer contagem (do mais frequente para o menos).
  • -k N e -t SEP — ordenam por uma coluna específica com um separador à escolha.
  • -u — remove duplicados ao ordenar, um atalho para sort | uniq.
  • -h — ordena tamanhos «humanos» como 2K, 15M ou 1G.

uniq — agregar e contar

  • uniq — remove linhas duplicadas consecutivas.
  • -c — prefixa cada linha com o número de ocorrências. É a base de qualquer contagem em shell.
  • -d / -u — mostram só as linhas repetidas, ou só as que ocorrem uma única vez.
  • -i — ignora maiúsculas e minúsculas na comparação.

wc, tr e head — rematar o funil

  • wc -l — conta linhas; -w conta palavras e -c conta bytes. No fim de um pipeline, transforma uma lista numa métrica.
  • tr -s ' ' — comprime sequências de espaços num só; tr -d '\r' apaga os retornos de carro do Windows; tr 'A-Z' 'a-z' normaliza para minúsculas.
  • head -5 — fica com as cinco primeiras linhas; tail faz o mesmo com as últimas.

Pipelines em cibersegurança

O top de IPs de um access log. É o pipeline mais famoso da resposta a incidentes. Extrai o IP de cada pedido, ordena para juntar os iguais, conta, reordena pelas contagens e fica com o topo:

cut -d' ' -f1 access.log | sort | uniq -c | sort -rn | head -5
     10 203.0.113.66
      4 198.51.100.23
      3 192.0.2.14
      2 198.51.100.7
      2 192.0.2.55

Um IP com dez vezes mais pedidos do que os restantes, num intervalo curto, é a assinatura típica de um scan, de scraping agressivo ou do início de um ataque de negação de serviço. A mesma receita, trocando o campo, responde a outras perguntas: com o campo do código HTTP conta-se quantos 404 (enumeração de ficheiros) e 401 (força bruta em páginas de autenticação) o servidor devolveu; num log de autenticação, extrai-se o utilizador ou a origem das tentativas falhadas.

Triagem sem SIEM. Nem todos os incidentes acontecem onde há um SIEM a indexar tudo. Num servidor isolado, numa máquina virtual esquecida ou num sistema comprometido em que só há acesso por consola, estes cinco utilitários existem sempre — fazem parte de qualquer instalação mínima. Saber montá-los de cor é a diferença entre responder em minutos ou esperar por ferramentas.

Medir a dimensão do problema. Antes de decidir bloquear, convém quantificar: wc -l diz quantos pedidos houve no total, e cut ... | sort -u | wc -l diz quantas origens distintas. Se 80% do tráfego vem de meia dúzia de endereços, um bloqueio cirúrgico na firewall resolve; se vem de milhares, o cenário é outro — provavelmente uma botnet — e a resposta também.

Experimente no simulador interativo

A simulação abaixo mostra um access log fictício à esquerda e um terminal à direita. Cada chip acrescenta um estágio ao pipeline — pela ordem em que clicar — e a faixa de fases mostra quantas linhas saem de cada estágio; clique numa fase para ver o output intermédio que o comando seguinte recebe. O botão Demonstrar tudo percorre uma investigação guiada, do log em bruto ao top de IPs, e os botões Anterior/Seguinte permitem avançar ao seu ritmo.

Erros comuns e boas práticas

  • Usar uniq sem sort antes. O uniq só agrega repetidos consecutivos; sem ordenar primeiro, as contagens saem fragmentadas e erradas.
  • Esquecer o -n no sort. Ordenar números como texto põe 964 depois de 8123. Contagens, bytes e tamanhos pedem sempre sort -n (ou -h para unidades humanas).
  • Confiar cegamente nos separadores. Uma linha com dois espaços seguidos desvia os campos do cut. Normalize com tr -s ' ' ou valide o resultado antes de tirar conclusões — dados reais são sujos.
  • O cat inútil. cat ficheiro | cut ... funciona, mas o cut (tal como sort, uniq, head e wc) aceita o ficheiro diretamente como argumento — um processo a menos.
  • Ignorar a localização (locale). A ordem do sort depende da locale; em scripts e análises reprodutíveis, use LC_ALL=C sort — além de previsível, é bastante mais rápido em ficheiros grandes.
  • Concluir sem quantificar. Um head -5 mostra o topo, mas convém sempre juntar o total (wc -l) para perceber o peso real desses primeiros lugares.

Conclusão

O poder desta família de comandos não está em nenhum deles individualmente — está no pipe que os liga. cut extrai, sort ordena, uniq -c conta, sort -rn hierarquiza e head remata: cinco estágios que transformam qualquer log num relatório instantâneo, em qualquer máquina Linux, sem instalar nada. Se quer levar estas competências mais longe — da linha de comandos à análise de incidentes e ao hardening de servidores — conheça os serviços de formação e consultoria da HJFR no nosso catálogo de serviços, e reveja também o artigo sobre o useradd desta mesma série.

Este artigo faz parte da série “Comandos Linux, um a um” do blog HJFR — fique atento aos próximos comandos.