sexta-feira, 26 de janeiro de 2024

Grep com Contexto

O grep geralmente é usado em arquivos orientados a linhas. De quando em vez aparece algo mais complicado.

Se precisamos de mais contexto, podemos usar -B (before) e -A (after) para indicar quantas linhas queremos de antes e depois do que for encontrado:


  grep -B 4 -A 3 ERROR log.txt
  

E assim podemos ver 3 linhas para frente e 4 para trás.

Se o arquivo tiver delimitadores, podemos usar uma mágica do Perl. Considere o arquivo abaixo:


Registro 1
Nome: Fulano
Endereço: Rua Torta, 1
Sexo: M
Fim
Registro 2
Nome: Beltrana
Endereço: Rua Reta, 12
Sexo: F
Fim

Se eu quiser filtrar todos os registros com "Sexo: F", posso usar a variável $/, que indica o que é um separador de linha.


$ perl -ne "BEGIN{$/='Fim'} print if /Sexo: F/" pessoas.txt

Registro 2
Nome: Beltrana
Endereço: Rua Reta, 12
Sexo: F
$ perl -ne "BEGIN{$/='Fim'} print if /Sexo: M/" pessoas.txt
Registro 1
Nome: Fulano
Endereço: Rua Torta, 1
Sexo: M

O BEGIN serve para executarmos a atribuição apenas uma vez, porque a opção -n coloca tudo dentro de um "while(<>) {}". Mas se não nos importamos com isso, podemos simplificar com:


 perl -ne "$/='Fim'; print if /Sexo: M/" pessoas.txt
 

Podemos até incluir o \n no valor de $/ para não surgirem linhas vazias nos resultados. Para isso, também temos usar o qq() (quoted string) para não termos problemas com as aspas duplas:


 perl -ne "$/=qq(Fim\n); print if /Sexo: M/" pessoas.txt
 

Se os registros não tiverem os mesmos terminadores ou se o arquivo contiver outras estruturas que não nos interessam, podemos usar o operador flip-flop:


#!/usr/bin/perl
open(my $file, '<', $ARGV[0]);

my ($block, $found);
while(<$file>) {
    if(/^Registro/ .. /^Fim/) {
        $found=1 if /Sexo: M/;
        $block.=$_;
    } else {
        print $block if $found;
        undef $block;
        $found=0;
    }
}
print $block if $found;
  

Esse script recebe o nome do arquivo como parâmetro. A mágica acontece no "if(/^Registro/ .. /^Fim/)". O operador começa a retornar verdadeiro quando encontra Registro e passa a retornar falso quando encontra Fim. O resto do arquivo cai no else. O resto do script é óbvio.

Então, temos 3 opções para buscas progressivamente complexas em arquivos. Perl, como de costume, salva o dia.

Nenhum comentário:

Postar um comentário