Wie wird nur die nächste Zeile nach der übereinstimmenden angezeigt?

218
grep -A1 'blah' logfile

Dank dieses Befehls für jede Zeile, in der 'blah' enthalten ist, erhalte ich die Ausgabe der Zeile, die 'blah' enthält, und die nächste Zeile, die in der Protokolldatei folgt. Es mag einfach sein, aber ich kann keinen Weg finden, die Zeile mit 'blah' wegzulassen und nur die nächste Zeile in der Ausgabe anzuzeigen.

facha
quelle
71
Ich denke, viele Leute werden hierher kommen, um nach der -A1Option zu suchen
Mirelon
Dann benutze ich dies, um meine öffentliche IP zu erhalten. :)curl whatismyip.org | grep -A1 'Your IP Address'
Shrekuu
6
In ähnlicher Weise -B1, -B2, -B3, -A1, -A2, -A3. . .
Meawoppl
5
@shrek curl icanhazip.com (kein grep benötigt) :)
alexyorke
1
Ihre Frage beantwortet meine Frage ... -A1. Vielen Dank!
S3DEV

Antworten:

181

du kannst es mit awk versuchen:

awk '/blah/{getline; print}' logfile
Michał Šrajer
quelle
3
Für alle, die wirklich ein grep -A2-Äquivalent wollten (was ich brauchte), isst getline einfach die Linie und fährt mit dem nächsten fort. Also, was für mich funktionierte, war buchstäblich nurawk '/blah/{getline; getline; print}' logfile
Aaron R.
160

wenn du bei grep bleiben willst:

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

oder

sed -n '/blah/{n;p;}' logfile
Kent
quelle
2
@ Kent, danke für den Tipp. Von meinem POV aus ist grep viel lesbarer und leichter zu verstehen als sed oder die awk-Antwort, die als beste Antwort markiert ist ... aber ich
bin
2
Für diejenigen, die neugierig sind, was -v tut: -v --invert-match Invertiert den Sinn der Übereinstimmung, um nicht übereinstimmende Linien auszuwählen. (-v wird von POSIX angegeben.)
Sammi
2
Ich mag diese Antwort wirklich, aber es wird nicht funktionieren, wenn Sie zwei Zeilen in einer Reihe haben, die "bla" enthalten und die zweite erhalten möchten (weil es "die nächste Zeile nach der übereinstimmenden" ist). Ich kann mir keinen Anwendungsfall dafür vorstellen, aber es ist erwähnenswert.
Tin Wizard
Die Top-Lösung ist nur "ok". Wenn die zweite Zeile auch "bla" enthält, haben Sie ein echtes Durcheinander in Ihren Händen.
Riwalk
32

Piping ist dein Freund ...

Verwenden Sie grep -A1diese Option , um die nächste Zeile nach einem Match anzuzeigen, und leiten Sie das Ergebnis an eine tailZeile weiter.

cat logs/info.log | grep "term" -A1 | tail -n 1
weisjohn
quelle
1
Wenn sich "term" in der letzten Zeile befindet, wird die Zeile zurückgegeben, die "term" anstelle von nichts enthält, was Sie möchten.
Onnonymous
Schwanz -n 1 ergibt nur die letzte Zeile der gesamten Datei
Sebastian
13

Tolle Antwort von raim, war sehr nützlich für mich. Es ist trivial, dies zu erweitern, um z. B. Zeile 7 nach dem Muster zu drucken

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

Wenn diese nächsten Zeilen niemals 'bla' enthalten, können Sie sie filtern mit:

grep -A1 blah logfile | grep -v blah

Die Verwendung von cat logfile | ...ist nicht erforderlich.

ott--
quelle
5

Im Allgemeinen stimme ich zu, dass Sie hier viel Grep verlangen und dass ein anderes Tool die bessere Lösung sein könnte. Aber in einer eingebetteten Umgebung möchte ich dies möglicherweise nicht haben sedoder awknur tun. Ich habe festgestellt, dass die folgende Lösung funktioniert (solange es sich nicht um zusammenhängende Übereinstimmungen handelt):

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

Passen Sie sie grundsätzlich an, indem Sie für jede Übereinstimmung 1 Kontextzeile anhängen und diese dann durch eine inverse Übereinstimmung Ihres ursprünglichen Musters leiten, um diese zu entfernen. Dies bedeutet natürlich, dass Sie davon ausgehen können, dass Ihr Muster nicht in der "nächsten" Zeile angezeigt wird.

Travis Griggs
quelle
5

Bisher wurden viele gute Antworten auf diese Frage gegeben, aber ich vermisse immer noch eine, die ich awknicht benutze getline. Da es im Allgemeinen nicht notwendig ist, zu verwenden getline, würde ich mich für Folgendes entscheiden:

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

oder

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

Die Logik besteht immer darin, die Zeile zu speichern, in der "bla" gefunden wird, und dann die Zeilen zu drucken, die eine Zeile später sind.

Prüfung

Beispieldatei:

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

Holen Sie sich alle Zeilen nach "bla". Dies druckt ein weiteres "bla", wenn es nach dem ersten erscheint.

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

Holen Sie sich alle Zeilen nach "bla", wenn sie selbst nicht "bla" enthalten.

$ awk '/blah/ {f=NR} f && NR==f+1' a
1
4
7
fedorqui 'SO hör auf zu schaden'
quelle
5

Ich kenne keine Möglichkeit, dies mit grep zu tun, aber es ist möglich, awk zu verwenden, um das gleiche Ergebnis zu erzielen:

awk '/blah/ {getline;print}' < logfile
raimue
quelle
@jww Es gibt keinen Unterschied. Wie Sie an den Zeitstempeln sehen können, die nur wenige Minuten voneinander entfernt sind, habe ich ungefähr zur gleichen Zeit geantwortet.
Raimue
4

Perl Einzeiler Alarm

Nur zum Spaß ... drucke nur eine Zeile nach dem Spiel

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

Noch mehr Spaß ... drucken Sie die nächsten zehn Zeilen nach dem Spiel

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

ein bisschen schummeln, da es tatsächlich zwei Befehle gibt

beasy
quelle
Können Sie $. == $ als nächstes erklären? Natürlich ist es mehr als ein numerischer Vergleich der aktuellen Zeilennummer mit $ next, aber ich verstehe nicht, wie / warum es funktioniert.
Keith Bentrup
Mehr geht es nicht. $. == $next && printist das gleiche wieprint if $. == $next
beasy
Ah, ich verstehe jetzt. Vielen Dank! Von den beiden Teilen ist jeder wahr und wird in separaten, benachbarten Iterationen der Schleife ausgeführt. Ich nehme an, wenn es darum ging, nach einer Übereinstimmung eine Zeile zu drucken, würden Sie die Reihenfolge umkehren wollen (würde sich eher so verhalten grep -A1). Wenn Sie nur die nächsten Zeilen drucken möchten, aber niemals eine Zeile mit einer Übereinstimmung, behalten Sie diese Reihenfolge bei. (Ich beachte nur, wie $ next für aufeinanderfolgende Spiele überfallen würde)
Keith Bentrup
3

Es sieht so aus, als würden Sie dort das falsche Werkzeug verwenden. Grep ist nicht so raffiniert, ich denke, Sie möchten awk als Werkzeug für den Job einsetzen:

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

Wenn Sie irgendwelche Probleme haben, lassen Sie es mich wissen, ich denke, es lohnt sich, ein bisschen awk zu lernen, es ist ein großartiges Werkzeug :)

ps Dieses Beispiel gewinnt keinen "nutzlosen Gebrauch des Katzenpreises";) http://porkmail.org/era/unix/award.html

dummMunky
quelle
3
Übrigens können Sie "$ 0" im Druck überspringen.
Michał Šrajer
0

grep / Pattern / | Schwanz -n 2 | Kopf -n 1

Tail first 2 und dann last last, um nach dem Match genau die erste Zeile zu erhalten.

Amrit Pal Singh
quelle