Tail Grep - Imprima linhas circunvizinhas até que o padrão seja correspondido

1

Então aqui está minha exigência.

Estou acompanhando um arquivo de log e digitando nele.
Eu quero obter algum contexto em cada resultado grep ..
Mas o contexto deve ser "até que um padrão seja correspondido" e não o número de linhas (que é o que o grep -A/-B/-C oferece).

Por exemplo,
Diga aqui é meu log ..

[l] é prefixado em todas as linhas de log. Além disso, haverá prefixo de [logTypeA] ou [logTypeB]

[l][logTypeA] - Log line 1
[l][logTypeB] - Log line 2 
[l][logTypeA] - Log line 3 
.... 

Random data about Log line 3
....

[l][logTypeB] - Log line 4

Agora meu se meu comando tail foi tail -f log_file.log | grep "[logTypeA]" , Eu teria uma saída de

[l][logTypeA] - Log line 1
[l][logTypeA] - Log line 3 

Mas eu preciso de informações contextuais para meu resultado grep, e esse contexto NÃO é um número de linhas, mas sim até que um padrão específico seja correspondido (neste caso [l]).

No exemplo, quero que meu resultado grep seja

[l][logTypeA] - Log line 1
[l][logTypeA] - Log line 3 
.... 

Random data about Log line 3
....

A partir daqui ( Como mostrar as linhas após cada correspondência do grep até outra correspondência específica? ), tentei o comando sed no meu tail like

tail -f log_file.log | sed '/\[logTypeA\]/,/\[l\]/p'

Mas isso não parece funcionar.

Alguma idéia?

    
por SatheeshJM 17.06.2017 / 16:41

2 respostas

1

Este é um padrão extremamente comum com o Awk. Colete linhas relacionadas em "registros", imprima o registro quando tiver coletado tudo se corresponder a uma condição específica.

tail -f file |
awk '/\[l]/ { if (p && stored) print stored; stored = ""; p=0 }
    /\[logTypeA]/ { p=1 }
    { stored = stored (stored ? ORS : "") $0 }
    END { if (p) print stored }'

A condição END realmente não faz sentido com um fluxo sem fim de tail -f , mas incluo-a como uma boa medida e para evitar falhas de teste irritantes quando o último registro com o qual deseja testar deve ser impresso , mas não ficará sem a cláusula END .

    
por 19.06.2017 / 04:43
0

Eu provavelmente acabaria fazendo isso com um perl one-liner. Você pode fazê-lo em sed mas parece que está começando a bater contra a parte "não-intencional turing-completeness" do sed.

One-liner Perl (o perl -ne é realmente o take away aqui)

echo  '[l] boring\nboring data\n[l] boring\n[l]interesting\ndata\ndata\n[l]boring' |  perl -ne '
    if (/\[l\].*interesting/ ) { print $_; $collect=1 ; }
    elsif (/\[l\]/) {$collect=0 }
    elsif ($collect) {print $_}'

Para referência, aqui está o one-liner sed que faz a mesma coisa. (Recursos do sed usado: b para conseguir um switch, T para obter execução condicional).

echo  '[l] boring\nboring data\n[l] boring\n[l\]interesting\ndata\ndata\n[l]boring' |  sed -nE '/\[l\].*interesting/ {
p;
s/.*/collect/ ; x ; # store collect marker in the pattern space
b; # terminate processing
}

/\[l\]/ {
s/.*// ; x; # clear hold flag
b
}

/./ {
x;
s/collect/collect/;
T; x; p # print if we are collecting
}
'
    
por 19.06.2017 / 18:35