Como grep para texto em um arquivo e exibir o parágrafo que tem o texto?

22

Abaixo está o texto no arquivo:

Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good

Eu preciso do grep para "42B" e obter a saída do texto acima, como:

Pseudo name=Apple
Code=42B
state=fault

Alguém tem ideia de como conseguir isso usando grep / awk / sed ?

    
por Jaya William 14.07.2013 / 02:24

5 respostas

36

com awk

awk -v RS='' '/42B/' file

RS= altera o separador de registro de entrada de uma nova linha para linhas em branco. Se algum campo em um registro contiver /42B/ , imprima o registro.

'' (a string nula) é um valor mágico usado para representar linhas em branco de acordo com POSIX :

If RS is null, then records are separated by sequences consisting of a <newline> plus one or more blank lines, leading or trailing blank lines shall not result in empty records at the beginning or end of the input, and a <newline> shall always be a field separator, no matter what the value of FS is.

Os parágrafos de saída não serão separados, pois o separador de saída permanece como uma nova linha. Para garantir que haja uma linha em branco entre os parágrafos de saída, defina o separador de registro de saída como duas novas linhas:

awk -v RS='' -v ORS='\n\n' '/42B/' file
    
por 14.07.2013 / 04:46
14

Supondo que os dados estejam estruturados de modo que seja sempre a linha antes e depois, você pode usar as opções -A (após) e -B (antes) do grep para incluir a linha 1 antes do jogo e 1 linha depois:

$ grep -A 1 -B 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

Se você quiser as mesmas linhas numéricas antes e depois do termo de pesquisa, use a opção -C (context):

$ grep -C 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

Se você quiser ser mais rigoroso ao combinar as várias linhas, use a ferramenta pcregrep , para corresponder a um padrão em várias linhas:

$ pcregrep -M 'Pseudo.*\n.*42B.*\nstate.*' sample.txt
Pseudo name=Apple
Code=42B
state=fault

O padrão acima corresponde ao seguinte:

  • -M - várias linhas
  • 'Pseudo.*\n.*42B.*\nstate.*' - corresponde a um grupo de strings em que a primeira string começa com a palavra "Pseudo" seguida por todos os caracteres até o final da linha \n , seguido por todos os caracteres até a string "42B" seguida por todos os caracteres até outro fim de linha ( \n ), seguido pela string "state" seguido por quaisquer caracteres.
por 14.07.2013 / 02:34
4

Provavelmente, existe uma maneira igualmente fácil de fazer isso com o awk, mas no perl:

cat file | perl -ne 'BEGIN { $/="\n\n" }; print if $_ =~ /42B/;'

Isso basicamente diz para dividir o arquivo em blocos delimitados por linhas em branco e, em seguida, imprimir apenas os blocos que correspondem à sua expressão regular.

    
por 14.07.2013 / 02:45
4

O grep de alguns tipos de Unix tem o sinal -p para "parágrafo". Eu sei AIX faz .

grep -p 42B <myfile>

faria exatamente o que você está pedindo por lá. YMMV e GNU grep não possuem este flag.

    
por 17.11.2015 / 10:11
2

Uma outra solução de perl, sem uma linha vazia:

perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo

Exemplo

% perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo
Pseudo name=Apple
Code=42B
state=fault

% cat foo
Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good
    
por 07.07.2015 / 16:34