¿Cómo mostrar solo la siguiente línea después de la coincidente?

218
grep -A1 'blah' logfile

Gracias a este comando para cada línea que tiene 'blah', obtengo el resultado de la línea que contiene 'blah' y la siguiente línea que sigue en el archivo de registro. Puede ser simple, pero no puedo encontrar una manera de omitir la línea que tiene 'bla' y solo mostrar la siguiente línea en la salida.

facha
fuente
72
Creo que mucha gente vendrá aquí buscando la -A1opción
mirelon
Luego uso esto para obtener mi IP pública. :)curl whatismyip.org | grep -A1 'Your IP Address'
shrekuu
66
Del mismo modo -B1, -B2, -B3, -A1, -A2, -A3. . .
meawoppl
55
@shrek curl icanhazip.com (no se necesita grep) :)
alexyorke
1
Su pregunta respondió a mi pregunta ... -A1. ¡Gracias!
S3DEV

Respuestas:

181

puedes probar con awk:

awk '/blah/{getline; print}' logfile
Michał Šrajer
fuente
3
Para cualquiera que realmente quisiera un grep -A2 equivalente (que es lo que necesitaba), getline simplemente se come la línea y pasa a la siguiente. Entonces, lo que funcionó para mí fue literalmente soloawk '/blah/{getline; getline; print}' logfile
Aaron R.
160

si quieres apegarte a grep:

grep -A1 'blah' logfile|grep -v "blah"

o

sed -n '/blah/{n;p;}' logfile
Kent
fuente
2
@Kent, gracias por el consejo. Desde mi Punto de vista, sin embargo, grep es mucho más legible y fácil de entender en comparación con sed o la respuesta awk marcado como mejor respuesta .... pero es sólo a mí tal vez :)
icasimpan
2
Para aquellos curiosos acerca de lo que hace -v: -v --invert-match Invierte el sentido de coincidencia, para seleccionar líneas no coincidentes. (-v es especificado por POSIX.)
Sammi
2
Realmente me gusta esta respuesta, pero no funcionará si tiene dos líneas seguidas que contienen "bla" y desea obtener la segunda (porque es "la siguiente línea después de la coincidente"). No puedo pensar en ningún caso de uso para eso fuera de mi cabeza, pero vale la pena señalar.
Tin Wizard
La solución principal es simplemente "ok". Si la segunda línea también tiene "bla", tendrás un verdadero desastre en tus manos.
Riwalk
32

Piping es tu amigo ...

Use grep -A1para mostrar la siguiente línea después de una coincidencia, luego canalice el resultado taily solo tome 1 línea,

cat logs/info.log | grep "term" -A1 | tail -n 1
Weisjohn
fuente
1
Si "term" está en la última línea, esto devolverá la línea que contiene "term" en lugar de nada, lo que desea.
Onnónimo el
tail -n 1 solo dará como resultado la última línea del archivo completo
Sebastian
13

Gran respuesta de Raim, fue muy útil para mí. Es trivial extender esto para imprimir, por ejemplo, la línea 7 después del patrón

awk -v lines=7 '/blah/ {for(i=lines;i;--i)getline; print $0 }' logfile
souter
fuente
9

Si las siguientes líneas nunca contienen 'bla', puede filtrarlas con:

grep -A1 blah logfile | grep -v blah

El uso de cat logfile | ...no es necesario.

ott--
fuente
5

En general, estoy de acuerdo en que estás pidiendo mucha información aquí, y que otra herramienta puede ser la mejor solución. Pero en un entorno incrustado, es posible que no quiera tener sedo awksimplemente hacer esto. Encontré que la siguiente solución funciona (siempre que no sean coincidencias contiguas):

grep -A1 AT\+CSQ wvdial.out | grep -v AT\+CSQ

Básicamente, combínelos, agregando 1 línea de contexto para cada coincidencia, y luego canalice eso a través de una coincidencia inversa de su patrón original para eliminarlos. Por supuesto, esto significa que puede asumir que su patrón no aparece en la línea "siguiente".

Travis Griggs
fuente
5

Muchas buenas respuestas se han dado a esta pregunta hasta ahora, pero aún extraño una con awkno usarla getline. Como, en general , no es necesario usarlo getline, elegiría:

awk ' f && NR==f+1; /blah/ {f=NR}' file  #all matches after "blah"

o

awk '/blah/ {f=NR} f && NR==f+1' file   #matches after "blah" not being also "blah"

La lógica siempre consiste en almacenar la línea donde se encuentra "bla" y luego imprimir las líneas que están una línea después.

Prueba

Archivo de muestra:

$ cat a
0
blah1
1
2
3
blah2
4
5
6
blah3
blah4
7

Obtenga todas las líneas después de "bla". Esto imprime otro "bla" si aparece después del primero.

$ awk 'f&&NR==f+1; /blah/ {f=NR}' a
1
4
blah4
7

Obtenga todas las líneas después de "bla" si no contienen "bla".

$ awk '/blah/ {f=NR} f && NR==f+1' a
1
4
7
fedorqui 'así que deja de dañar'
fuente
5

No conozco ninguna forma de hacer esto con grep, pero es posible usar awk para lograr el mismo resultado:

awk '/blah/ {getline;print}' < logfile
raimue
fuente
@jww No hay diferencia. Como puede ver en las marcas de tiempo que están a solo minutos de diferencia, parece que respondí casi al mismo tiempo.
raimue
4

alerta perl one-liner

solo por diversión ... imprima solo una línea después del partido

perl -lne '$next=($.+1)if/match/;$.==$next&&print' data.txt

aún más divertido ... imprime las siguientes diez líneas después del partido

perl -lne 'push@nexts,(($.+1)..($.+10))if/match/;$.~~@nexts&&print' data.txt

un poco trampa ya que en realidad hay dos comandos

beasy
fuente
¿Puedes explicar $. == $ siguiente? Claramente es más que una comparación numérica del número de línea actual con $ next, pero no entiendo cómo / por qué funciona.
Keith Bentrup
No es más que eso. $. == $next && printes lo mismo queprint if $. == $next
beasy
Ah, ya veo ahora. ¡Gracias! De las 2 partes, cada una es verdadera y se ejecuta en iteraciones adyacentes separadas del bucle. Supongo que si el punto fuera imprimir una línea después de una coincidencia, querría invertir el orden (se comportaría más como grep -A1). Si desea imprimir solo las siguientes líneas pero nunca una línea con una coincidencia, entonces debería mantener este orden. (solo señalando cómo $ next sería golpeado por partidos consecutivos)
Keith Bentrup
3

Parece que estás usando la herramienta incorrecta allí. Grep no es tan sofisticado, creo que quieres avanzar a awk como la herramienta para el trabajo:

awk '/blah/ { getline; print $0 }' logfile

Si tienes algún problema, házmelo saber, creo que vale la pena aprender un poco de awk, es una gran herramienta :)

ps Este ejemplo no gana un 'premio de uso inútil del gato';) http://porkmail.org/era/unix/award.html

tontoMunky
fuente
3
Por cierto, puede omitir "$ 0" en la impresión.
Michał Šrajer
0

grep / Patrón / | cola -n 2 | cabeza -n 1

Sigue los primeros 2 y luego el último para obtener exactamente la primera línea después del partido.

Amrit Pal Singh
fuente