Imprimir linha correspondente e enésima linha da linha correspondente

18

Estou tentando imprimir a linha correspondente e a quarta linha da linha correspondente (linha que contém a expressão que estou procurando).

Eu tenho usado o seguinte código: sed -n 's/^[ \t]*//; /img class=\"devil_icon/,4p' input.txt

Mas isso apenas imprime a linha correspondente.

Isso imprime apenas a quarta linha. awk 'c&&!--c;/img class=\"devil_icon/{c=4}' input.txt

Preciso imprimir apenas a linha correspondente e a quarta linha.

debal
fonte
Use egrep "pattern" -A4
Valentin Bajrami
@ val0x00ff que imprime as linhas entre também .. ou seja: ele imprime próximos 4 linhas a partir da linha combinado
Debal
você está dizendo "Estou tentando imprimir a linha correspondente e a quarta linha da linha correspondente". Isto grep -A 4 "pattern" file | sed -n '4p'faz exatamente o que você quer, a menos que eu estou mal-entendido que você
Valentin Bajrami
não, não faz. A saída do código acima foi </td>que não é a linha 4
Debal

Respostas:

18

No awk, você faria da seguinte maneira

awk '/pattern/{nr[NR]; nr[NR+4]}; NR in nr' file > new_file`

ou

awk '/pattern/{print; nr[NR+4]; next}; NR in nr' file > new_file`

Explicação

A primeira solução encontra todas as linhas correspondentes pattern. Quando encontra uma correspondência, armazena o número do registro ( NR) na matriz nr. Ele também armazena o quarto registro NRna mesma matriz. Isso é feito pelo nr[NR+4]. Cada registro ( NR) é verificado para ver se está presente na nrmatriz; nesse caso, o registro é impresso.

A segunda solução funciona essencialmente da mesma maneira, exceto quando encontra a patternlinha impressa e, em seguida, armazena o quarto registro à frente na matriz nre depois passa para o próximo registro. Então, quando awkencontrar esse 4º registro, o NR in nrbloco será executado e imprimirá esse registro +4 depois.

Exemplo

Aqui está um exemplo de arquivo de dados sample.txt.

$ cat sample.txt 
1
2
3
4 blah
5
6
7
8
9
10 blah
11
12
13
14
15
16

Usando a 1ª solução:

$ awk '/blah/{nr[NR]; nr[NR+4]}; NR in nr' sample.txt 
4 blah
8
10 blah
14

Usando a segunda solução:

$ awk '/blah/{print; nr[NR+4]; next}; NR in nr' sample.txt 
4 blah
8
10 blah
14
Valentin Bajrami
fonte
3
Bom, +1. Você está usando muitos awkatalhos aqui. Você pode adicionar uma breve explicação (coisas como impressão estão implícitas no awk e que matrizes são associativas etc.)?
terdon
concordo com @terdon, por favor, poderia explicar um pouco o código.
Debal 24/08/13
@slm Obrigado por melhorar e fornecer a resposta completa!
Valentin Bajrami
11
Obrigado pela resposta, eu também aprendi algo novo.
slm
4
sed -n 's/^[ \t]*/; /img class=\"devil_icon/,+4 { 3,5d ; p }' input.txt

Estou simplesmente adicionando uma exclusão das linhas apropriadas antes da impressão { 3,5d ; p }.

Drav Sloan
fonte
sua expressão produz um erro: sed: -e expression #1, char 18: unknown option to s'`
minerals
4

Você pode tentar a -Aopção com grep, que especifica quantas linhas após a linha correspondente devem ser impressas. Junte isso sede você obterá as linhas necessárias.

grep -A 4 pattern input.txt | sed -e '2,4d'

Usando sed, excluímos da segunda linha até a quarta.

Barun
fonte
3
Isso pressupõe uma única correspondência patternno arquivo.
terdon
2

Aqui está uma maneira no Perl que pode lidar com um número arbitrário de linhas correspondentes:

perl -ne '/pattern/ && do{$c=$.; print}; $.==$c+4 && print' file > new_file`

Em Perl. a variável especial $.é o número da linha atual. Assim, cada vez que encontro uma linha correspondente pattern, imprimo-a e salvo o número da linha como $c. Em seguida, imprimo novamente quando o número da linha atual é 4 a mais do que o impresso anteriormente.

terdon
fonte
0
awk 'c&&!--c;/img class=\"devil_icon/{c=4};/img class=\"devil_icon/' input.txt

Você está essencialmente fazendo uma busca e substituição. Você pode adicionar apenas uma descoberta ao mesmo comando e ele imprimirá os dois :)

awk 'c&&!--c;/pattern/{c=4};/pattern/' input.txt
bacoNx1000
fonte