Expressões regulares no shell
Esta aula aprofunda o uso de expressões regulares no shell Linux/Bash, diferenciando as básicas (BRE) e estendidas (ERE), mostrando como aplicá-las em grep, sed e awk, com exemplos práticos e exercícios para fixação.
Expressões regulares (regex) são uma ferramenta poderosa para busca e manipulação de texto, amplamente utilizadas em scripts shell. Nesta aula, você aprenderá as diferenças entre as expressões regulares básicas (BRE) e estendidas (ERE), e como aplicá-las nos comandos grep, sed e awk, que são pilares do processamento de texto no Linux.
Dominar regex no shell é essencial para automatizar tarefas de filtragem, extração e transformação de dados em arquivos e streams. Vamos explorar desde os conceitos fundamentais até exemplos práticos que você pode usar imediatamente em seus scripts.
Básicas vs estendidas
As expressões regulares podem ser classificadas em dois tipos principais: básicas (BRE) e estendidas (ERE). A diferença está principalmente na sintaxe e nos metacaracteres disponíveis. As BRE são mais antigas e exigem que alguns caracteres sejam escapados com barra invertida para terem significado especial, enquanto as ERE não precisam desse escape adicional.
Por exemplo, na BRE, para usar o quantificador +, você precisa escrever \+. Já na ERE, basta usar +. Da mesma forma, os parênteses de agrupamento em BRE são \( e \), enquanto em ERE são ( e ).
Os comandos grep, sed e awk têm opções para selecionar o tipo de expressão regular. Por exemplo, no grep você pode usar -E para ERE e -G (ou nenhuma opção) para BRE. No sed, a opção -E ou -r ativa ERE, enquanto no awk as expressões são sempre ERE (na maioria das implementações).
Em grep, sed, awk
Cada comando tem sua própria forma de aplicar regex. O grep filtra linhas que correspondem a um padrão, o sed é um editor de fluxo que pode substituir ou modificar texto, e o awk é uma linguagem de programação orientada a texto que processa linhas e campos. Todos eles suportam regex, mas com nuances.
grep: usa regex para encontrar linhas correspondentes. Você pode usar opções como -E (ERE), -i (ignorar maiúsculas), -v (inverter a seleção), entre outras.
# Exemplo com grep -E (ERE)
grep -E "^[0-9]{3}-[0-9]{4}$" telefones.txtsed: usa regex principalmente em comandos de substituição (s/.../.../) e endereçamento de linhas. Por padrão, usa BRE, mas com -E você ativa ERE.
# Substituir qualquer número de 4 dígitos por "####" usando ERE
sed -E 's/[0-9]{4}/####/g' dados.txtawk: a sintaxe de regex é semelhante ao ERE, e você pode usar em padrões de linha ou em funções de string. O awk é mais poderoso para processamento de campos.
# Imprimir linhas onde o campo 2 contém "erro" (case insensitive)
awk -F: '$2 ~ /erro/i' arquivo.txtDiferenças
As principais diferenças entre BRE e ERE afetam a escrita do padrão. Vamos listar os caracteres que têm significado especial e como são representados em cada tipo:
- Quantificadores:
*(zero ou mais) é igual em ambos;+(um ou mais) e?(zero ou um) são ERE, em BRE precisam ser escapados:\+e\?. - Alternância:
|(ou) é ERE, em BRE é\|. - Agrupamento: parênteses
(...)em ERE, em BRE são\(...\). - Chaves:
{m,n}(intervalo) é ERE, em BRE é\{m,n\}.
Outra diferença importante é o suporte a classes de caracteres POSIX, como [:alpha:], [:digit:], que funcionam em ambos, mas é bom lembrar que dentro de colchetes.
No grep, por padrão, ele usa BRE, mas com -E você obtém ERE. Algumas versões têm -P para Perl regex, que é ainda mais avançada, mas não é padrão em todos os sistemas.
Exemplos
Vamos ver exemplos práticos que combinam regex com grep, sed e awk.
Exemplo 1: Validar endereços de e-mail (simplificado)
# Usando grep -E para encontrar e-mails
grep -E "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" emails.txtExemplo 2: Extrair IPs de um arquivo de log
# Com grep -o para extrair apenas os IPs
grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" access.log | sort -uExemplo 3: Substituir múltiplos espaços por um único
# Usando sed -E
sed -E 's/[[:space:]]+/ /g' texto.txtExemplo 4: Somar valores de um campo com awk
# Somar valores numéricos no campo 3 (separados por vírgula)
awk -F, '$3 ~ /^[0-9]+$/ {soma += $3} END {print "Total:", soma}' dados.csvExemplo 5: Usar backreferences em sed
# Trocar ordem de nome e sobrenome (ex.: "João Silva" -> "Silva, João")
echo "João Silva" | sed -E 's/([A-Za-z]+) ([A-Za-z]+)/\2, \1/'Boas práticas e observações
Quando estiver escrevendo scripts, prefira usar ERE (-E) para maior clareza, a menos que precise de compatibilidade máxima com sistemas antigos. Sempre teste suas regex em um arquivo pequeno antes de aplicar em dados reais. Use aspas simples para proteger o padrão da expansão do shell. Lembre-se de escapar caracteres como \ quando necessário.
Além disso, esteja ciente de que o awk tem sua própria sintaxe de regex, mas é compatível com a maioria dos recursos ERE. Para tarefas complexas, considere usar perl ou python que têm suporte a regex mais poderoso, mas isso foge ao escopo desta aula.
Exercícios
Escreva um comando grep para encontrar linhas em um arquivo que contenham a palavra "erro" ou "falha", ignorando maiúsculas/minúsculas, usando ERE.
✓ Resposta:grep -E -i "erro|falha" arquivo.txtUse sed para substituir todas as ocorrências de "foo" por "bar" em um arquivo, mas apenas quando "foo" estiver no início da linha.
✓ Resposta:sed -E 's/^foo/bar/' arquivo.txtCom awk, imprima apenas as linhas em que o segundo campo (separado por espaço) contém um número de telefone no formato (XX) XXXXX-XXXX.
✓ Resposta:awk '$2 ~ /^\([0-9]{2}\) [0-9]{5}-[0-9]{4}$/' arquivo.txtExplique a diferença entre BRE e ERE em relação aos parênteses e à alternância, e dê um exemplo de uso em grep.
✓ Resposta: Em BRE, parênteses e barra vertical devem ser escapados:\(,\),\|. Em ERE, usamos diretamente(,),|. Exemplo: para buscar "gato" ou "cachorro", em BRE:grep 'gato\|cachorro'; em ERE:grep -E 'gato|cachorro'.Crie um comando que use awk para extrair a soma de todos os números contidos em uma coluna de um arquivo CSV, onde os números podem ter casas decimais.
✓ Resposta:awk -F, '$3 ~ /^[0-9]+(\.[0-9]+)?$/ {soma += $3} END {printf "%.2f\n", soma}' arquivo.csv