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/nulldescarta 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.csvO 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.txtCorrespondê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.logA 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.txtO 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 *.pyDepuraçã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
- Use âncoras:
grep "^error" huge.logé mais rápido quegrep "error" huge.log - Remova
.*desnecessários:grep "error" log.txté suficiente (.*error.*é lento) - Use
-Fpara strings fixas:grep -F "exact_string" file.txtpula 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.
Leia antes: -delete e -exec não podem ser desfeitos
O -delete remove arquivos sem nenhuma lixeira. O -exec chmod reescreve a permissão de todos os arquivos que casarem. O que acontece quando dá errado se resume a dois pontos.
- Se a condição de busca for ampla demais, arquivos que você nunca quis tocar são excluídos ou alterados.
- Como no
rm, arquivos excluídos não podem ser restaurados sem backup.
Como testar com segurança é sempre dividir o trabalho em duas etapas.
- Execute primeiro com
-printe confira a lista de alvos com os próprios olhos. - Quando a lista estiver correta, troque
-printpor-deleteou-exec.
# Etapa 1: apenas listar os alvos (nao altera nada) find /tmp -name "*.tmp" -print # Etapa 2: excluir depois que a lista estiver correta find /tmp -name "*.tmp" -delete
Escreva sempre o -delete depois das condições. O find avalia na ordem informada, então find /tmp -delete -name "*.tmp" exclui antes de o -name ser avaliado, apagando tudo em /tmp.
Pratique dentro de um diretório de trabalho que você mesmo criou em /tmp. Nunca pratique contra /, /etc ou /var.
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.txtColetar 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
-printantes de-deleteou-exec - [ ] Restringiu a busca a um diretório concreto em vez de
/