Processamento de texto com expressões regulares

LinuxBeginner
Pratique Agora

Introdução

Uma expressão regular descreve um texto pela sua estrutura, e não por uma única sequência exata. A mesma linguagem de padrões aparece em várias ferramentas do Linux, mas cada ferramenta a utiliza de uma maneira diferente: grep seleciona ou extrai correspondências, sed transforma um fluxo e awk combina padrões com ações orientadas por campos.

Você começará usando âncoras e classes de caracteres, depois passará para repetição estendida e extração. Em seguida, visualizará transformações antes de salvá-las e terminará com seleção e agregação de campos. Os padrões são colocados entre aspas para que o shell passe os caracteres especiais à ferramenta de texto, em vez de interpretá-los.

Encontre linhas com a estrutura básica de expressões regulares

Nesta etapa, você usará texto literal, âncoras e classes de caracteres para descrever posições em linhas inteiras.

Inspecione o arquivo de prática:

cd /home/labex/project/regex-lab
nl -ba contacts.txt

O texto literal encontra correspondências em qualquer posição da linha:

grep 'active' contacts.txt

^ fixa o padrão no início da linha, e $ fixa o padrão no final. Encontre o registro de Alice e os registros que terminam com um número de dois dígitos:

grep '^Alice|' contacts.txt
grep '[0-9][0-9]$' contacts.txt

Dentro dos colchetes, uma classe de caracteres corresponde a um caractere. [ABC] significa A, B ou C:

grep '^[ABC]' contacts.txt | tee abc-contacts.txt

Esse comando produz as linhas de Alice, Bob e Carol. Salve também as correspondências numéricas ancoradas:

grep '[0-9][0-9]$' contacts.txt > two-digit-values.txt

Use expressões regulares estendidas e extraia correspondências

Nesta etapa, você usará expressões regulares estendidas para trabalhar com alternativas e repetição. Depois, extrairá apenas a substring correspondente.

grep -E habilita operadores como + (um ou mais), ? (zero ou um) e | (alternativa). Encontre os campos de status completos active ou pending:

cd /home/labex/project/regex-lab
grep -E '\|(active|pending)\|' contacts.txt

Um padrão semelhante a um endereço de e-mail pode ser construído em partes:

  • [[:alnum:]._-]+ corresponde a um ou mais caracteres permitidos na parte local;
  • @ é um caractere literal;
  • [[:alnum:].-]+ corresponde ao corpo do domínio;
  • \.[[:alpha:]]{2,} corresponde a um ponto seguido por um sufixo com duas ou mais letras.

Use -o para exibir apenas as substrings correspondentes:

grep -Eo '[[:alnum:]._-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}' contacts.txt | tee emails.txt

Numere as linhas correspondentes e conte os endereços extraídos:

grep -En '\|(active|pending)\|' contacts.txt
wc -l < emails.txt | tr -d ' ' > email-count.txt
cat email-count.txt

dave_at_example.com não corresponde ao padrão porque não contém @.

Visualize transformações com Sed

Nesta etapa, você transformará um fluxo com sed sem alterar a entrada.

Uma substituição tem o formato s/pattern/replacement/flags. Substitua apenas o primeiro a de cada linha e, depois, substitua todos os a minúsculos usando a flag g:

cd /home/labex/project/regex-lab
sed 's/a/A/' contacts.txt
sed 's/a/A/g' contacts.txt

Use outro delimitador quando o próprio texto contiver barras ou quando outro delimitador deixar o comando mais claro. Substitua os domínios de e-mail por redacted.invalid:

sed -E 's#@[[:alnum:].-]+\.[[:alpha:]]{2,}#@redacted.invalid#g' contacts.txt

Os endereços do Sed selecionam as linhas que receberão um comando. Aplique a substituição de status somente às linhas que contêm exatamente o campo |inactive|:

sed '/|inactive|/s/|inactive|/|disabled|/' contacts.txt | tee contacts-preview.txt

Confirme que o arquivo original ainda contém inactive:

grep '|inactive|' contacts.txt

Crie um arquivo limpo com Sed

Nesta etapa, você combinará vários comandos sed e salvará o fluxo transformado em um novo arquivo.

O cabeçalho de services.csv deve permanecer inalterado. Nas linhas de dados, normalize warn para warning e adicione o sufixo ms ao campo numérico final. -e fornece vários comandos, e o endereço 2,$ limita esses comandos às linhas de 2 até o final:

cd /home/labex/project/regex-lab
sed -E -e '2,$ s/,warn,/,warning,/' -e '2,$ s/([0-9]+)$/\1ms/' services.csv | tee services-clean.csv

Aqui, os parênteses capturam os dígitos finais, e \1 reutiliza essa captura na substituição.

Compare os arquivos original e novo:

diff -u services.csv services-clean.csv || true

O status diferente de zero do diff é esperado, pois a saída foi alterada intencionalmente; || true permite que uma sequência de comandos copiada continue.

Selecione campos e faça agregações com Awk

Nesta etapa, você usará awk quando a tarefa exigir tanto a estrutura dos campos quanto cálculos.

-F, define a vírgula como separador de entrada. Exiba o serviço e o status somente nas linhas de dados; NR é o número do registro atual:

cd /home/labex/project/regex-lab
awk -F, 'NR > 1 {print $1, $2}' services.csv

Selecione as linhas cujo terceiro campo numérico seja maior que 200:

awk -F, 'NR > 1 && $3 > 200 {print $1, $3}' services.csv | tee slow-services.txt

Acumule um total e uma contagem e, depois, calcule uma média no bloco END. printf controla o formato numérico:

awk -F, 'NR > 1 {sum += $3; count++} END {printf "average_latency=%.1f\n", sum/count}' services.csv | tee latency-summary.txt

Os padrões do Awk determinam em quais registros uma ação será executada; campos como $1 e $3 tornam os cálculos estruturados mais fáceis de ler.

Resumo

Você construiu padrões de expressões regulares usando âncoras, classes, alternativas e repetição; usou grep para selecionar e extrair; usou sed para visualizar e salvar transformações; e usou awk para selecionar e agregar dados com base em campos. No próximo Challenge, você aplicará essas ideias sem receber uma sequência completa de comandos.