Imprimir línea coincidente y enésima línea desde la línea coincidente

18

Estoy tratando de imprimir la línea coincidente y la cuarta línea desde la línea coincidente (línea que contiene la expresión que estoy buscando).

He estado usando el siguiente código: sed -n 's/^[ \t]*//; /img class=\"devil_icon/,4p' input.txt

Pero esto solo imprime la línea coincidente.

Esto imprime solo la cuarta línea. awk 'c&&!--c;/img class=\"devil_icon/{c=4}' input.txt

Necesito imprimir tanto la línea coincidente como la cuarta línea solamente.

debatir
fuente
Uso egrep "pattern" -A4
Valentin Bajrami
@ val0x00ff que imprime las líneas intermedias también ... es decir: imprime las siguientes 4 líneas a partir de la línea coincidente
debal
usted está diciendo "Estoy tratando de imprimir la línea coincidente y la cuarta línea desde la línea coincidente". Esto grep -A 4 "pattern" file | sed -n '4p'hace exactamente lo que quieres, a menos que te malinterprete
Valentin Bajrami
No, no lo hace. El resultado del código anterior fue el </td>que no es la cuarta línea
debal

Respuestas:

18

En awk, lo harías de la siguiente manera

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

o

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

Explicación

La primera solución encuentra todas las líneas que coinciden pattern. Cuando encuentra una coincidencia, almacena el número de registro ( NR) en la matriz nr. También almacena el cuarto registro de NRla misma matriz. Esto lo hace el nr[NR+4]. NRLuego se comprueba cada registro ( ) para ver si está presente en la nrmatriz, de ser así, se imprime el registro.

La segunda solución funciona esencialmente de la misma manera, excepto cuando se encuentra con patternque imprime esa línea, y luego almacena el cuarto registro delante de él en la matriz nr, luego pasa al siguiente registro. Luego, cuando awkencuentre este cuarto registro, el NR in nrbloque se ejecutará e imprimirá este registro +4 allí después.

Ejemplo

He aquí un ejemplo de archivo de datos, sample.txt.

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

Usando la primera solución:

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

Usando la segunda solución:

$ awk '/blah/{print; nr[NR+4]; next}; NR in nr' sample.txt 
4 blah
8
10 blah
14
Valentin Bajrami
fuente
3
Niza, +1. Está utilizando muchos awkaccesos directos aquí, ¿podría agregar una breve explicación (cosas como la impresión está implícita en awk y que las matrices son asociativas, etc.)?
terdon
un acuerdo con @terdon por favor, ¿podría explicar un poco el código?
debal
@slm ¡Gracias por mejorar y proporcionar la respuesta completa!
Valentin Bajrami
1
Gracias por la respuesta, aprendí algo nuevo también.
slm
4
sed -n 's/^[ \t]*/; /img class=\"devil_icon/,+4 { 3,5d ; p }' input.txt

Simplemente estoy agregando una eliminación de las líneas apropiadas, antes de imprimir { 3,5d ; p }.

Drav Sloan
fuente
su expresión produce un error: sed: -e expression #1, char 18: unknown option to s'`
minerales
4

Puede probar la -Aopción con grep, que especifica cuántas líneas después de la línea coincidente deben imprimirse. Combine esto sedy obtendrá las líneas requeridas.

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

Usando sed, eliminamos el de la segunda línea hasta la cuarta.

Barun
fuente
3
Esto supone una sola coincidencia patternen el archivo.
terdon
2

Aquí hay una manera en Perl que puede manejar un número arbitrario de líneas coincidentes:

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

En perl. La variable especial $.es el número de línea actual. Entonces, cada vez que encuentro una coincidencia de línea pattern, la imprimo y guardo su número de línea como $c. Luego imprimo nuevamente cuando el número de línea actual es 4 más que el impreso anteriormente.

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

Básicamente estás haciendo una búsqueda y reemplazo. Puede agregar solo un hallazgo en el mismo comando y los imprimirá a ambos :)

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