GREP / SED ou AWK: Imprimir parágrafo inteiro em um arquivo na correspondência de padrão [duplicado]

8

Eu tenho um arquivo com centenas de parágrafos de cerca de 15 linhas cada. Preciso procurar um padrão, digamos Ocorrência: 1 . Se esse padrão for encontrado no para, eu preciso imprimir o parágrafo inteiro. Observe que os parágrafos são separados por dois novos caracteres de linha.

Eu tentei a linha de código abaixo e isso obviamente imprime a primeira ocorrência no arquivo. De alguma forma, não consigo usar um loop e imprimir todas essas ocorrências.

sed -n '1,/Occurrence: 1/p' ystdef.txt | tail -9 > ystalarm.txt

Posso usar o sinalizador g (global) com sed para que isso funcione? Se sim, como?

Note que estou ciente dos comandos grep -A/B/C , mas eles não funcionam no meu terminal Cygwin.

    
por Irfan N 09.06.2014 / 15:01

3 respostas

9

Você pode usar o “modo de parágrafo” do awk, onde os registros de entrada são delimitados por sequências de pelo menos duas novas linhas.

awk -v RS= '/Occurance: 1/' ystdef.txt

Observe que os parágrafos serão impressos todos juntos (com uma única nova linha entre o conteúdo deles). Awk não permite que você combine o separador de saída com o separador de entrada (exceto com algumas extensões do GNU awk), mas você pode facilmente padronizar o separador de parágrafo para duas novas linhas.

awk -v RS= ORS='\n\n' '/Occurance: 1/' ystdef.txt

Se você não quiser uma nova linha extra no final:

awk -v RS= '/Occurance: 1/ {if (not_first) print ""; print; not_first=1}' ystdef.txt
    
por 10.06.2014 / 02:37
5

Aqui está no GNU sed :

sed '/./{H;$!d};x;/SEARCH/!d'

Sintaxe portátil / POSIX:

sed -e '/./{H;$!d;}' -e 'x;/SEARCH/!d'

Se uma linha contiver um ou mais caracteres, ela será anexada a H old space e, se for ! , a $ última linha será excluída. Isso significa que cada linha que não é em branco é armazenada e removida da saída.

Portanto, se uma linha não for d eleted, então sed e x alterará o conteúdo da retenção e do espaço padrão. Isso torna o espaço de espera apenas uma linha em branco e o padrão ocupa todas as linhas desde a última linha em branco.

sed , em seguida, aborda o padrão /SEARCH/ . Se ! não o encontrou, d elimina o espaço de padrão sem imprimir, senão o parágrafo é impresso por padrão.

Aqui está em uma função de shell com sua pergunta como entrada:

Observação - os dados processados são comentados abaixo para facilitar a leitura em face do destaque do código deste site. Funcionará como está ou sem os hashes.

_pgraph() { 
    sed '/./{H;$!d};x;/'"$1"'/!d'
} <<\DATA
#    I have a file with hundreds of paragraphs of
#    around 15 lines each. I need to search for a
#    pattern, say Occurance: 1. If this pattern is
#    found in the para, I need to print the entire
#    paragraph. Note that the paragraps are seperared
#    by 2 new line characters.

#    I have tried the below line of code and this
#    obviously prints the first occurence in the
#    file. I am somehow unable to use a loop and
#    print all such occurances.

#    sed -n '1,/Occurance: 1/p' ystdef.txt | tail -9 >
#    ystalarm.txt Can I use the g (global) flag with
#    sed to make this work? If yes, how?

#    Note that I am aware of the grep -A/B/C commands
#    but they wont work on my cygwin terminal.
DATA

Agora eu posso fazer:

_pgraph Note

###OUTPUT

#    I have a file with hundreds of paragraphs of
#    around 15 lines each. I need to search for a
#    pattern, say Occurance: 1. If this pattern is
#    found in the para, I need to print the entire
#    paragraph. Note that the paragraps are seperared
#    by 2 new line characters.

#    Note that I am aware of the grep -A/B/C commands
#    but they wont work on my cygwin terminal.

Ou mais especificamente:

_pgraph 'Note that I'

#    Note that I am aware of the grep -A/B/C commands
#    but they wont work on my cygwin terminal.

Você pode fazer o mesmo para qualquer arquivo sem anexar uma entrada literal à própria função simplesmente removendo tudo de <<\DATA para DATA na definição da função e executando-a da seguinte forma:

_pgraph 'PATTERN' </path/to/input.file
    
por 09.06.2014 / 21:14
4

Você pode usar o "modo de parágrafo" no Perl:

perl -ne 'BEGIN{ $/ = "" } print if /pattern/' input
    
por 09.06.2014 / 15:17

Tags