Como Usar find, grep e awk - Tutorial de Busca de Texto no Linux

Como Usar find, grep e awk - Tutorial de Busca de Texto no Linux

O que você vai conseguir fazer

  • Escolher entre find, grep e awk a partir do objetivo
  • Ler e escrever âncoras, quantificadores e classes de caracteres
  • Combinar condições e ações do find para executar lotes com segurança

Pré-requisitos (leia estes primeiro)

Quando você já está confortável com os comandos básicos do Linux, os três próximos a aprender são find, grep e awk. Com esses três, você resolve busca de arquivos, investigação de logs e agregação em uma única linha.

Este guia de fundamentos cobre três pontos: o papel de cada comando e como escolher entre eles, os fundamentos de expressões regulares que valem para os três e os recursos de busca do find.

O Que Você Vai Aprender

  • Você vai conseguir escolher entre find, grep e awk a partir do seu objetivo.
  • Você vai conseguir ler e escrever âncoras, quantificadores e classes de caracteres.
  • Você vai conseguir combinar condições e ações do find para executar lotes com segurança.

Para quem é: quem já usou pelo menos uma vez comandos básicos como ls, cd e cat.

Pré-requisitos: find e grep precisam de sudo quando os arquivos pertencem a outro usuário. Alguns exemplos usam pipes (|) e redirecionamento (>). Se isso for novo para você, leia primeiro Fundamentos de Pipe e Redirecionamento.

Termos definidos antes de começar

Cada termo abaixo é definido uma única vez, aqui.

  • Uma expressão regular é uma forma de descrever "textos com esta forma" como um padrão. Também é chamada de regex ou regexp. Este artigo usa "regex".
  • Um metacaractere é um símbolo como ^, $, . ou * que carrega um significado especial em vez de representar a si mesmo. Também é chamado de caractere especial.
  • Uma âncora é um metacaractere que aponta para uma posição: início de linha, fim de linha ou limite de palavra. Ela nunca casa com um caractere em si.
  • Um quantificador define quantas vezes o padrão anterior se repete. Também é chamado de operador de repetição.
  • Uma classe de caracteres é uma forma como [0-9], que significa "qualquer caractere único deste intervalo".
  • Escapar é colocar \ antes de um metacaractere para que ele seja tratado como o símbolo literal.
  • A saída de erro padrão (stderr) é a saída por onde correm as mensagens de erro. 2>/dev/null descarta essa saída.

Visão Geral e Seleção de Comandos

Conclusão: find localiza arquivos, grep busca conteúdo, awk processa dados.

Primeiro, entenda as características e casos de uso de cada comando. Escolher o comando certo é o primeiro passo para um trabalho eficiente.

find: Busca de Arquivos e Diretórios

  • Buscar arquivos por nome
  • Filtrar por tamanho ou data
  • Buscar por permissões ou proprietário
  • Processamento em lote de arquivos encontrados

Especialidade: "Encontrar arquivos quando você não sabe onde estão".

find /home -name "*.txt" -size +1M

grep: Busca de Conteúdo de Texto

  • Buscar texto dentro de arquivos
  • Busca avançada usando regex
  • Análise de arquivos de log
  • Inspeção de arquivos de configuração

Especialidade: "Encontrar texto específico dentro de arquivos".

grep -r "ERROR" /var/log/

-r significa recursivo: ele desce pelos níveis do diretório informado. A maioria dos arquivos em /var/log/ pertence ao root, então use sudo grep -r "ERROR" /var/log/ quando não for possível ler.

awk: Processamento de Texto e Manipulação de Dados

  • Extrair e calcular dados de colunas
  • Processar arquivos CSV
  • Agregar arquivos de log
  • Conversão de formato

Especialidade: "Processar, agregar e transformar dados".

awk '{sum+=$3} END {print sum}' sales.csv

O awk lê a entrada uma linha por vez e trata cada item separado por espaço como um campo (coluna). $1 é a primeira coluna, $3 a terceira e NF a quantidade de colunas. O exemplo acima soma a terceira coluna e mostra o resultado quando todas as linhas foram lidas (END).

Fluxo de Decisão

Situação Comando a usar
Não sabe onde os arquivos estão find
Quer encontrar texto dentro de arquivos grep
Quer processar ou agregar dados awk

Masterclass de Expressões Regulares

Conclusão: Domine âncoras, quantificadores e classes em BRE, ERE e PCRE.

Expressões regulares são essenciais para desbloquear o verdadeiro poder de find, grep e awk. Domine padrões desde o básico até os imediatamente utilizáveis em trabalho de produção.

Tipos de Expressões Regulares

A regex tem três dialetos. O mesmo padrão pode ser interpretado de forma diferente conforme a ferramenta, então comece por essa distinção.

Tipo Abrv. Ferramentas Características
Regex Básica BRE grep, sed, vi Metacaracteres precisam de escape
Regex Estendida ERE egrep, grep -E, awk Sintaxe mais intuitiva
Regex Compatível com Perl PCRE grep -P, perl Mais poderosa (lookahead/lookbehind)

O grep usa BRE se nada for indicado. Acrescente -E para passar a ERE quando quiser escrever + ou ? diretamente.

Âncoras de Posição

# Linhas comecando com ERROR
grep "^ERROR" logfile.txt

# Linhas terminando com .log
grep "\.log$" filelist.txt

# A palavra "port" (exclui "report" etc.)
grep -E "\bport\b" config.txt

Classes de Caracteres

# Enderecos IP 192.168.1.x
grep "192\.168\.1\." access.log

# Formato de hora (HH:MM)
grep "[0-9][0-9]:[0-9][0-9]" log.txt

# Linhas contendo caracteres nao alfanumericos
grep "[^a-zA-Z0-9]" data.txt

Quantificadores

# Zero ou mais (error e failed na mesma linha)
grep "error.*failed" log.txt

# Um ou mais (ERE)
grep -E "[0-9]+" data.txt

# Zero ou um (http ou https)
grep -E "https?" urls.txt

# Entre n e m ocorrencias (numeros de 2-4 digitos)
grep -E "[0-9]{2,4}" data.txt

Correspondência Avançada de Padrões

Agrupamento e OR:

# Multiplas palavras-chave com OR
grep -E "(error|warning|critical)" log.txt

Lookahead e Lookbehind (PCRE):

# Numeros antes de "yen"
grep -P "\d+(?=yen)" price.txt

# "test" nao seguido por ".txt"
grep -P "test(?!\.txt)" filelist.txt

# Numeros apos sinal de $
grep -P "(?<=\$)\d+" invoice.txt

Padrões Práticos de Regex

Análise de Log:

# Enderecos IPv4
grep -E "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" access.log

# Formato de data Apache
grep -E "\[[0-9]{2}/[A-Z][a-z]{2}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2} [+-][0-9]{4}\]" access.log

# Agregacao de codigos de status HTTP
grep -E "\" [1-5][0-9]{2} " access.log | awk '{print $9}' | sort | uniq -c

# Niveis de log
grep -E "\b(DEBUG|INFO|WARN|ERROR|FATAL|CRITICAL)\b" app.log

A agregação de status usa $9 porque, no formato combined do Apache, o status é o nono campo. O User-Agent é dividido nos espaços, então a quantidade de colunas varia por linha e uma posição contada a partir do fim, como $(NF-1), não pode ser usada.

Validação de Dados:

# Enderecos de e-mail (simples)
grep -E "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b" contacts.txt

# URLs (http/https)
grep -E "https?://[^[:space:]\"']+" webdata.txt

O exemplo de URL usa [^[:space:]...] em vez de [^\s...] porque dentro de uma expressão de colchetes ([ ]) o \s não é lido como a classe de espaços. [^\s"'] significa "qualquer coisa exceto barra invertida, s, " e '", então ele para assim que a URL contiver um s. Dentro dos colchetes, use a classe POSIX [:space:].

Análise de Código:

# Definicoes de funcao (JavaScript/Python)
grep -E "^(function|def)\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(" *.js *.py

# Declaracoes de variaveis (JavaScript)
grep -E "^(var|let|const)\s+[a-zA-Z_][a-zA-Z0-9_]*" *.js

# Comentarios TODO/FIXME
grep -E "(TODO|FIXME|XXX|HACK|NOTE):" -n *.py

Depuração de Regex

Construa regexes complexas de forma incremental.

# Passo 1: Linhas com digitos
grep "[0-9]" test.txt

# Passo 2: Um ou mais digitos
grep "[0-9]\+" test.txt

# Passo 3: Apenas digitos
grep "^[0-9]\+$" test.txt

Use -o para verificar correspondências parciais:

echo "test123abc456" | grep -o "[0-9]\+"
123
456

Escape BRE vs ERE

Escrever "192.168.1. seguido de um ou mais caracteres" em cada dialeto fica assim.

  • BRE: escape no quantificador + - grep "192\.168\.1\..\+" access.log
  • ERE: quantificador + escrito direto - grep -E "192\.168\.1\..+" access.log

Nos dois, \. é um ponto literal e . é qualquer caractere único. No BRE, apenas o quantificador precisa de escape; o . não precisa. Escrito como grep "192\.168\.1\.\+", o \+ se aplica ao \. anterior, o que muda o sentido para "um ou mais pontos".

Otimização de Desempenho

Três dicas para regex mais rápida

  1. Use âncoras: grep "^error" huge.log é mais rápido que grep "error" huge.log
  2. Remova .* desnecessários: grep "error" log.txt é suficiente (.*error.* é lento)
  3. Use -F para strings fixas: grep -F "exact_string" file.txt pula o motor de regex

Comando find: Dominando a Busca de Arquivos

Conclusão: find filtra por nome, tamanho ou data, depois executa ações nos resultados.

find é um comando poderoso que permite buscar no sistema de arquivos de qualquer forma que você precise.

Sintaxe Básica

find [caminho_de_busca] [condicoes] [acoes]

Ele localiza arquivos que correspondem às condições no caminho de busca, depois executa ações.

Busca por Nome

# Arquivos com extensao .txt
find /home -name "*.txt"

# Arquivos comecando com "config"
find . -name "config*"

# Busca .log sem diferenciar maiusculas/minusculas
find /var -iname "*.LOG"

Busca por Tipo de Arquivo

O -type restringe a busca a um tipo de entrada: f para arquivo regular, d para diretório e l para link simbólico (um "atalho" que aponta para outro arquivo; link simbólico, symlink e soft link significam a mesma coisa).

# Apenas arquivos regulares
find /home -type f

# Diretorios comecando com "log"
find /var -type d -name "log*"

# Links simbolicos
find /tmp -type l

Busca por Tamanho

O -size tem uma pegadinha: ele arredonda para cima na unidade indicada antes de comparar. Portanto -size -1k significa "menos de uma unidade de 1KB", o que casa apenas com arquivos de 0 byte. Um arquivo de 500 bytes é arredondado para 1KB e não casa.

# Maior que 100MB
find /var -size +100M

# Arquivos de 0 byte (arredondam para zero unidades)
find /home -size -1k

# Estritamente menor que 1024 bytes (c = bytes)
find /home -size -1024c

# Maior que 1GB e menor que 10GB (comparado depois do arredondamento)
find . -size +1G -size -10G

Para filtrar em um limite exato de bytes, use c (bytes) em vez de k, M ou G. Não há arredondamento, então o limite é o que você pretendia.

Busca por Data e Hora

Existem três condições de tempo. mtime (modification time) é quando o conteúdo mudou, atime (access time) é quando o arquivo foi lido e ctime (change time) é quando atributos como permissão ou proprietário mudaram. A unidade é o dia: -7 significa "nos últimos 7 dias" e +30 significa "há mais de 30 dias".

# Modificado nos ultimos 7 dias (mtime)
find /home -mtime -7

# Modificado ha mais de 30 dias
find /var/log -mtime +30

# Nao acessado por mais de 1 dia (atime)
find /tmp -atime +1

# Mais recente que reference.txt
find /home -newer reference.txt

Busca por Permissão e Proprietário

O -perm filtra por permissão. O bit setuid faz o programa rodar com os privilégios do proprietário do arquivo, e não de quem chamou, e por isso ele pode se tornar trampolim para escalada de privilégio e entra nas auditorias de segurança.

# Arquivos com permissao 755
find /home -perm 755

# Arquivos com bit setuid (verificacao de seguranca)
find / -perm -4000 2>/dev/null

# Arquivos pertencentes a www-data
find /var -user www-data

# Arquivos no grupo developers
find /home -group developers

Executar Ações

O verdadeiro poder do find é poder executar automaticamente ações nos arquivos encontrados. Essa também é a parte em que os acidentes acontecem com mais facilidade.

Excluir arquivos:

# Excluir arquivos temporarios em massa
find /tmp -name "*.tmp" -delete

# Excluir arquivos de log com mais de 30 dias
find /var/log -name "*.log" -mtime +30 -delete

O -delete é executado pelo próprio find, o que é mais rápido e mais seguro que -exec rm {} \;. Ele também trata corretamente nomes que contenham espaços ou quebras de linha. Note que o -delete habilita implicitamente o -depth (processar primeiro os níveis mais profundos), então ele não pode ser combinado com -prune.

Alterar permissões:

# Definir arquivos PHP para 644
find /var/www -name "*.php" -exec chmod 644 {} \;

# Definir diretorios para 755
find /home -type d -exec chmod 755 {} \;

O {} é um marcador substituído por cada nome de arquivo encontrado, e \; indica "executar uma vez por arquivo". Trocar \; por + passa vários arquivos de uma vez, o que é mais rápido.

Permissões não podem ser restauradas sem registro

A exibição -rw-r--r-- do ls -l não pode ser convertida mecanicamente em um número para o chmod. Para criar um caminho de volta, salve as permissões numéricas em um arquivo antes de executar a mudança.

# Antes: salve as permissoes numericas em um arquivo
find /var/www -name "*.php" -exec stat -c '%a %n' {} + > ~/perm-backup.txt

# Para voltar atras: reescreva os valores salvos, linha por linha
while read -r mode path; do chmod "$mode" "$path"; done < ~/perm-backup.txt

Coletar informações:

# Mostrar detalhes de arquivos .txt
find /home -name "*.txt" -exec ls -lh {} \;

# Mostrar tamanhos de arquivos maiores que 100MB
find /var -size +100M -exec du -h {} \;

Boas Práticas

Limite o escopo de busca

Buscar a partir do diretório raiz (/) percorre o disco inteiro, então é lento. Em um servidor em produção isso também aumenta a carga de disco. Especifique um diretório inicial mais concreto.

  • Bom: find /var/log -name "*.log"
  • Ruim: find / -name "*.log"

Pressione Ctrl+C para interromper uma busca em andamento. A busca apenas lê, então interromper nunca danifica arquivos.

Suprima erros de permissão

Oculte mensagens de erro de diretórios inacessíveis com 2>/dev/null.

find / -name "*.txt" 2>/dev/null

Combine condições de forma eficiente

Empilhe múltiplas condições para precisão.

# Logs maiores que 1MB modificados nos ultimos 7 dias
find /home -name "*.log" -size +1M -mtime -7

Solução de Problemas

Conclusão: Quase todo problema é uma de quatro causas: falta de permissão, falta de aspas, dialeto de regex errado ou escopo de busca amplo demais.

Sintoma: enxurrada de Permission denied

Causa: a busca percorre diretórios para os quais você não tem permissão de leitura.

Verificação:

find /var -name "*.log"

Correção: descarte os erros ou empreste privilégios com sudo.

find /var -name "*.log" 2>/dev/null   # descarta os erros
sudo find /var -name "*.log"          # le com privilegio elevado

Sintoma: find . -name *.txt devolve algo inesperado

Causa: sem aspas, o shell expande *.txt antes de o find receber o padrão.

Verificação:

find . -name *.txt

Correção: sempre coloque o padrão de busca entre aspas.

find . -name "*.txt"

Sintoma: grep "[0-9]+" não casa com nada

Causa: o grep usa BRE por padrão, e ali o + é lido como um sinal de mais literal.

Verificação:

echo "abc123" | grep "[0-9]+"

Correção: passe para ERE com -E ou escape o +.

echo "abc123" | grep -E "[0-9]+"    # ERE
echo "abc123" | grep "[0-9]\+"      # BRE com escape

Sintoma: o grep nunca volta ao prompt

Causa: o nome do arquivo foi omitido, então o grep espera entrada pela entrada padrão.

Verificação: nada é exibido e o terminal aceita digitação.

Correção: interrompa com Ctrl+C e execute de novo com um nome de arquivo. Se a entrada deve vir de um pipe, forneça o comando que a produz.

grep -E "ERROR" app.log          # informe o arquivo
tail -100 app.log | grep "ERROR" # alimente por um pipe

Sintoma: o find nunca retorna

Causa: o escopo de busca é amplo demais (todo o /, por exemplo).

Verificação: interrompa com Ctrl+C e revise o caminho informado.

Correção: restrinja o diretório alvo. Limitar a profundidade com -maxdepth também ajuda.

find /home/user -maxdepth 3 -name "*.log"

Checklist de Conclusão

  • [ ] Escolheu o comando a partir do objetivo (localizar arquivo / buscar conteúdo / transformar dados)
  • [ ] Manteve em mente se a regex roda como BRE ou ERE
  • [ ] Confirmou os alvos com -print antes de -delete ou -exec
  • [ ] Restringiu a busca a um diretório concreto em vez de /

Próximos Passos

Nos fundamentos, você aprendeu como escolher entre find, grep e awk, os fundamentos de expressões regulares e as poderosas capacidades de busca do find. O guia avançado aprofunda as técnicas de grep e awk.