Linux: Busca em Texto — grep e Expressões Regulares
Encontrar aquela única linha entre milhares de arquivos — essa é a especialidade do grep. Provavelmente é o comando mais usado no Linux.
📋 Pré-requisitos: Você já deve conhecer
- Aula 13: Pipes e Filtros
1. O Que Você Vai Aprender
- Pesquisa básica do grep e opções comuns
- grep -r para busca recursiva em código
- Expressões regulares básicas
- Expressões regulares estendidas
- Análise de logs na prática
2. A História de Encontrar Código em Cem Arquivos
(1) O Problema: Mudar o Nome de uma API, Mas Não Saber Quais Arquivos a Usam
Alex precisava mudar todas as chamadas de requests.get para httpx.get em arquivos Python. O projeto tinha mais de 100 arquivos — abri-los um por um era impossível.
(2) grep Busca Recursiva
grep -rn "requests\.get" --include="*.py" src/
Saída:
src/api/client.py:15: response = requests.get(url, headers=headers)
src/api/users.py:42: data = requests.get(f"{API_URL}/users")
src/api/orders.py:78: result = requests.get(ORDER_URL)
3 arquivos com chamadas — encontrados em menos de um segundo.
(3) O Benefício: De Agulha no Palheiro à Precisão Absoluta
Alex criou o hábito: antes de mudar código, usar grep -rn para encontrar todas as localizações relacionadas, confirmar e só então começar a editar.
3. Pontos-Chave
(1) Uso Básico do grep
# Busca básica
grep "padrão" arquivo
# Combinações comuns de opções
grep -rn "TODO" src/ # Busca recursiva, mostra números de linha
grep -i "erro" log.txt # Ignorar maiúsculas/minúsculas
grep -v "debug" log.txt # Inverter correspondência (linhas que NÃO contêm debug)
grep -c "falhou" log.txt # Contar apenas
grep -l "main" *.py # Mostrar apenas nomes de arquivos que correspondem
grep -A5 -B5 "exception" log.txt # Mostrar 5 linhas antes e depois da correspondência
| Opção | Significado |
|---|---|
-i |
Ignorar maiúsculas/minúsculas |
-v |
Inverter correspondência (mostrar linhas que não correspondem) |
-c |
Apenas a quantidade de linhas correspondentes |
-n |
Mostrar números de linha |
-r ou -R |
Busca recursiva em subdiretórios |
-l |
Mostrar apenas nomes de arquivos que contêm correspondências |
-L |
Mostrar apenas nomes de arquivos que NÃO contêm correspondências |
-w |
Correspondência de palavras inteiras |
-A NUM |
Mostrar NUM linhas após a correspondência |
-B NUM |
Mostrar NUM linhas antes da correspondência |
-C NUM |
Mostrar NUM linhas antes e depois da correspondência |
(2) Expressões Regulares Básicas
| Metacaractere | Significado | Exemplo |
|---|---|---|
. |
Corresponde a qualquer caractere único | h.t corresponde a hit / hot / hat |
^ |
Início da linha | ^root corresponde a linhas que começam com root |
$ |
Fim da linha | bash$ corresponde a linhas que terminam com bash |
* |
Caractere anterior repetido 0 ou mais vezes | ab*c corresponde a ac / abc / abbc |
[abc] |
Qualquer caractere do conjunto | [Hh]ello corresponde a Hello ou hello |
[^abc] |
Caracteres que NÃO estão no conjunto | [^0-9] corresponde a caracteres não numéricos |
\< |
Início de palavra | \<root corresponde a root no início de uma palavra |
\> |
Fim de palavra | root\> corresponde a root no fim de uma palavra |
. corresponde a qualquer caractere único — se precisar corresponder a um ponto literal (como em um endereço IP), você precisa escapá-lo com barra invertida: grep "192\.168\." arquivo em vez de grep "192.168." arquivo (o último corresponderia incorretamente a 192X168Y etc.).
(3) Expressões Regulares Estendidas (grep -E)
No regex básico, +, ?, |, {}, () precisam ser escapados. O regex estendido usa esses metacaracteres diretamente (via grep -E ou egrep):
ℹ️ Nota: A principal diferença entre regex básico e estendido é que no regex estendido (
grep -E),+,?,|,{},()podem ser usados sem escape com barra invertida. No regex básico,grep "error\|warning"requer escape de|, enquantogrep -E "error|warning"não requer. Prefiragrep -Epara uma sintaxe mais clara.
| Metacaractere | Significado | Exemplo |
|---|---|---|
+ |
Caractere anterior repetido 1 ou mais vezes | ab+c corresponde a abc / abbc mas não a ac |
? |
Caractere anterior aparece 0 ou 1 vez | colou?r corresponde a color ou colour |
| ` | ` | Ou |
{n,m} |
Repetir n a m vezes | [0-9]{3,5} corresponde a números de 3-5 dígitos |
() |
Agrupamento | `(error |
(4) ▶ Exemplo: Busca Básica
# Buscar em um arquivo
grep "root" /etc/passwd
# root:x:0:0:root:/root:/bin/bash
# Ignorar maiúsculas/minúsculas
echo -e "Erro\nerro\nERRO" | grep -i "erro"
# Todas as três linhas correspondem
# Contar
grep -c "nologin" /etc/passwd
# Saída: 16
# Mostrar números de linha
grep -n "www-data" /etc/passwd
# 33:www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
Saída:
TEXTroot:x:0:0:root:/root:/bin/bash Erro erro ERRO 16 33:www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
(5) ▶ Exemplo: Inverter Correspondência
# Excluir linhas de comentário
grep -v "^#" /etc/ssh/sshd_config | grep -v "^$"
# Excluir logs de debug
grep -v "DEBUG" app.log | grep "ERROR"
# Excluir arquivos com certas extensões
ls -la | grep -v "\.md$"
Saída:
TEXTPort 22 PermitRootLogin no PasswordAuthentication no 2026-07-07 10:23:45 ERROR Database connection failed 2026-07-07 10:24:12 ERROR Timeout waiting for response drwxr-xr-x 2 alice alice 4096 Jul 7 10:00 src -rw-r--r-- 1 alice alice 1234 Jul 7 10:00 config.yaml
(6) ▶ Exemplo: Busca Recursiva em Código
# Buscar todos os comentários TODO no projeto
grep -rn "TODO\|FIXME\|HACK" --include="*.py" src/
# Buscar em tipos específicos de arquivo
grep -rn "def " --include="*.py" --include="*.js" .
# Buscar excluindo node_modules
grep -rn "api_key" --exclude-dir=node_modules --exclude-dir=.git .
# Mostrar apenas nomes de arquivos
grep -rl "class User" src/
Saída:
TEXTsrc/api/client.py:23:# TODO: Add retry logic src/models/user.py:45:# FIXME: Handle edge case src/utils/helpers.py:12:# HACK: Temporary workaround src/api/client.py:10:def get_user(user_id): src/models/user.py:5:def validate_email(email): config/settings.py:3:api_key = "sk-xxx" src/models/user.py src/auth.py
grep -rn é a combinação de ouro para busca em código — -r busca recursivamente em diretórios, -n mostra números de linha e --include limita os tipos de arquivo. Em projetos grandes, grep -rn "padrão" --include="*.py" src/ consegue localizar o código alvo em um segundo.
(7) ▶ Exemplo: Usando Contexto
# Mostrar 3 linhas antes e depois da correspondência
grep -C 3 "NullPointerException" app.log
# Mostrar 5 linhas após a correspondência
grep -A 5 "Traceback" python_error.log
# Mostrar 2 linhas antes da correspondência
grep -B 2 "500" access.log
Saída:
TEXT10:23:01 INFO Processing request 10:23:02 WARN Memory usage high 10:23:03 ERROR NullPointerException at UserService.java:45 10:23:04 INFO Retrying operation 10:23:05 WARN Connection pool low Traceback (most recent call last): File "app.py", line 42, in handle_request result = process(data) File "processor.py", line 15, in process return transform(input) ValueError: Invalid input data 192.168.1.100 - - [07/Jul/2026:10:23:44] "POST /api/data" 192.168.1.100 - - [07/Jul/2026:10:23:45] "POST /api/data HTTP/1.1" 500 0
(8) ▶ Exemplo: Regex na Prática
# Corresponder endereços de e-mail
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" contatos.txt
# Corresponder endereços IP
grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" access.log
# Corresponder URLs
grep -E "https?://[^ ]+" index.html
# Corresponder datas (YYYY-MM-DD)
grep -E "[0-9]{4}-[0-9]{2}-[0-9]{2}" logs/*.log
# Corresponder linhas que começam com dígito e terminam com letra
grep "^[0-9].*[a-zA-Z]$" arquivo.txt
Saída:
TEXTalice@example.com bob.smith@company.org contact@my-site.net 192.168.1.100 - - [07/Jul/2026] ... 10.0.0.45 - - [07/Jul/2026] ... https://example.com/api/users http://internal.server.local/status 2026-07-07 2026-07-08 1abc 23x
(9) ▶ Exemplo Abrangente: Análise de Erros em Log
#!/bin/bash
# analyze-errors.sh - Análise de erros em log
LOG_FILE="${1:-/var/log/syslog}"
echo "=== Relatório de Análise de Erros ==="
echo "Arquivo de origem: $LOG_FILE"
echo ""
echo "1. Contagem de erros por tipo:"
grep -i "erro" "$LOG_FILE" | awk '{print $5}' | sort | uniq -c | sort -rn | head -10
echo ""
echo "2. Últimos 5 erros:"
grep -i "erro" "$LOG_FILE" | tail -5
echo ""
echo "3. Alertas críticos (OOM / Disco cheio / Conexão recusada):"
grep -iE "oom|out of memory|disk full|no space left|connection refused" "$LOG_FILE"
echo ""
echo "4. Tendência de erros (por hora):"
grep -i "erro" "$LOG_FILE" | grep -oP "\d{2}:\d{2}" | cut -d: -f1 | sort | uniq -c | sort -rn
❓ Perguntas Frequentes
P: Qual é a diferença entre grep e regex? R: grep é uma ferramenta de linha de comando para buscar linhas que correspondem a um padrão em arquivos; expressões regulares (regex) são uma sintaxe para descrever padrões de texto. O grep suporta regex como padrões de busca, mas regex em si é apenas uma sintaxe que também pode ser usada em sed, awk, Python e muitas outras ferramentas e linguagens.
P:
grep -regrep -Rsão a mesma coisa? R: Basicamente sim.-Rsegue links simbólicos, enquanto-rnão por padrão. Qualquer um serve para uso diário.
P: Como faço para buscar ignorando maiúsculas/minúsculas? R: Use a opção
-i:grep -ir "erro" /var/log/.
P: Por que o grep às vezes não encontra caracteres chineses? R: Pode ser um problema de localidade. Caracteres chineses são multibyte em UTF-8, e o
grepcorresponde por byte por padrão. Tenteexport LANG=zh_CN.UTF-8ougrep -P(modo regex Perl).
P: Para que serve
grep -v? R: Inverter correspondência — produz linhas que NÃO correspondem ao padrão. Combinado com outras chamadas de grep, pode "excluir" certas linhas, por exemplo,grep -v "^#"exclui linhas de comentário,grep -v "^$"exclui linhas em branco.
📖 Resumo
grep "padrão" arquivobusca em arquivos,-rrecursivamente em diretórios,-nmostra números de linha- Regex básica:
.qualquer caractere,^início de linha,$fim de linha,*repetição,[abc]conjunto de caracteres - Regex estendida (
grep -E):+um ou mais,?zero ou um,|ou,()agrupamento -vinverte,-iignora maiúsculas/minúsculas,-cconta,-lmostra apenas nomes de arquivos-A/-B/-Cmostram linhas de contexto
📝 Exercícios
- Básico (Dificuldade ⭐): Busque em
/etc/passwdusuários que tenham/bin/bashcomo seu shell de login, depois busque erros em um arquivo de log e use-cpara contá-los - Intermediário (Dificuldade ⭐⭐): Busque recursivamente em um diretório de projeto por todos os comentários FIXME e TODO, depois use
grep -vpara excluir o diretório .git e contar o total de linhas de código - Avançado (Dificuldade ⭐⭐⭐): Use regex para corresponder todos os endereços IP em um arquivo de log, depois combine
sorteuniq -cpara contar ocorrências por IP e encontre os 10 IPs mais frequentes