Comment afficher uniquement la ligne suivante après celle correspondante?

218
grep -A1 'blah' logfile

Grâce à cette commande pour chaque ligne contenant 'blah', j'obtiens la sortie de la ligne qui contient 'blah' et la ligne suivante qui suit dans le fichier journal. Cela peut être simple, mais je ne trouve pas de moyen d'omettre la ligne qui a «bla» et d' afficher uniquement la ligne suivante dans la sortie.

facha
la source
72
Je pense que beaucoup de gens viendront ici à la recherche de l' -A1option
mirelon
Ensuite, je l'utilise pour obtenir mon adresse IP publique. :)curl whatismyip.org | grep -A1 'Your IP Address'
shrekuu
6
De même -B1, -B2, -B3, -A1, -A2, -A3. . .
meawoppl
5
@shrek curl icanhazip.com (pas besoin de grep) :)
alexyorke
1
Votre question a répondu à ma question ... -A1. Merci!
S3DEV

Réponses:

181

vous pouvez essayer avec awk:

awk '/blah/{getline; print}' logfile
Michał Šrajer
la source
3
Pour tous ceux qui veulent vraiment un équivalent grep -A2 (ce dont j'avais besoin), getline mange juste la ligne et passe à la suivante. Donc, ce qui a fonctionné pour moi était littéralement justeawk '/blah/{getline; getline; print}' logfile
Aaron R.
160

si vous voulez vous en tenir à grep:

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

ou

sed -n '/blah/{n;p;}' logfile
Kent
la source
2
@Kent, merci pour l'astuce. De mon POV cependant, grep est beaucoup plus lisible et facile à saisir par rapport à sed ou la réponse awk marquée comme meilleure réponse .... mais c'est juste moi peut-être :)
icasimpan
2
Pour ceux qui sont curieux de savoir ce que -v fait: -v --invert-match Inversez le sens de la correspondance, pour sélectionner les lignes qui ne correspondent pas. (-v est spécifié par POSIX.)
Sammi
2
J'aime vraiment cette réponse, mais cela ne fonctionnera pas si vous avez deux lignes d'affilée contenant "blah" et que vous voulez obtenir la seconde (parce que c'est "la ligne suivante après la correspondance"). Je ne peux penser à aucun cas d'utilisation pour cela du haut de ma tête, mais ça vaut la peine d'être noté.
Tin Wizard
La meilleure solution est simplement "ok". Si la deuxième ligne contient également "bla", vous aurez un vrai bordel entre vos mains.
riwalk
32

La tuyauterie est votre amie ...

Utilisez grep -A1pour afficher la ligne suivante après une correspondance, puis dirigez le résultat vers tailet ne saisissez qu'une seule ligne,

cat logs/info.log | grep "term" -A1 | tail -n 1
weisjohn
la source
1
Si "term" est sur la dernière ligne, cela retournera la ligne contenant "term" au lieu de rien, ce que vous voudriez.
Onnonymous
tail -n 1 ne donnera que la dernière ligne du fichier entier
Sebastian
13

Grande réponse de raim, m'a été très utile. Il est trivial de l'étendre pour imprimer par exemple la ligne 7 après le motif

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

Si les lignes suivantes ne contiennent jamais 'blah', vous pouvez les filtrer avec:

grep -A1 blah logfile | grep -v blah

L'utilisation de cat logfile | ...n'est pas nécessaire.

ott--
la source
5

En général, je suis d'accord que vous demandez beaucoup de grep ici, et qu'un autre outil peut être la meilleure solution. Mais dans un environnement intégré, je ne veux peut-être pas sedou awksimplement le faire. J'ai trouvé que la solution suivante fonctionne (tant qu'il ne s'agit pas de correspondances contiguës):

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

Fondamentalement, faites-les correspondre, en ajoutant 1 ligne de contexte pour chaque correspondance, puis redirigez-la via une correspondance inverse de votre modèle d'origine pour les supprimer. Cela signifie bien sûr que vous pouvez supposer que votre modèle n'apparaît pas dans la ligne "suivante".

Travis Griggs
la source
5

Jusqu'à présent, de nombreuses bonnes réponses ont été apportées à cette question, mais il me manque encore une question de awkne pas l'utiliser getline. Puisque, en général , il n'est pas nécessaire d'utiliser getline, j'irais pour:

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

ou

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

La logique consiste toujours à stocker la ligne où se trouve "blah" puis à imprimer les lignes qui se trouvent une ligne après.

Tester

Exemple de fichier:

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

Obtenez toutes les lignes après "bla". Cela imprime un autre "bla" s'il apparaît après le premier.

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

Obtenez toutes les lignes après "bla" si elles ne contiennent pas "bla" elles-mêmes.

$ awk '/blah/ {f=NR} f && NR==f+1' a
1
4
7
fedorqui 'SO arrête de nuire'
la source
5

Je ne connais aucun moyen de le faire avec grep, mais il est possible d'utiliser awk pour obtenir le même résultat:

awk '/blah/ {getline;print}' < logfile
raimue
la source
@jww Il n'y a pas de différence. Comme vous pouvez le voir sur les horodatages à quelques minutes d'intervalle, il semble que j'ai répondu à peu près au même moment.
raimue
4

alerte perl one-liner

juste pour le plaisir ... n'imprimer qu'une seule ligne après le match

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

encore plus de plaisir ... imprimez les dix lignes suivantes après le match

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

un peu tricher cependant car il y a en fait deux commandes

beasy
la source
Pouvez-vous expliquer $. == $ suivant? De toute évidence, c'est plus qu'une comparaison numérique du numéro de ligne actuel avec $ suivant, mais je ne comprends pas comment / pourquoi cela fonctionne.
Keith Bentrup
Ce n'est pas plus que ça. $. == $next && printest le même queprint if $. == $next
beasy
Ah, je vois maintenant. THX! Des 2 parties, chacune est vraie et s'exécute sur des itérations séparées et adjacentes de la boucle. Je suppose que si le but était d'imprimer une ligne après n'importe quelle correspondance, vous voudriez inverser l'ordre (se comporterait plus comme grep -A1). Si vous souhaitez imprimer uniquement les lignes suivantes mais jamais une ligne avec une correspondance, vous devez conserver cet ordre. (juste en notant comment $ next serait encombré pour des matchs consécutifs)
Keith Bentrup
3

Il semble que vous n'utilisiez pas le bon outil. Grep n'est pas si sophistiqué, je pense que vous voulez passer à awk comme outil pour le travail:

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

Si vous rencontrez des problèmes, faites-le moi savoir, je pense que cela vaut la peine d'apprendre un peu de awk, c'est un excellent outil :)

ps Cet exemple ne remporte pas une 'utilisation inutile du prix du chat';) http://porkmail.org/era/unix/award.html

sillyMunky
la source
3
BTW, vous pouvez ignorer "$ 0" en version imprimée.
Michał Šrajer
0

grep / Motif / | queue -n 2 | tête -n 1

Queue les 2 premiers, puis tête le dernier pour obtenir exactement la première ligne après le match.

Amrit Pal Singh
la source