Drucken Sie eine Zeile nur, wenn die nächste Zeile KEINE bestimmte Übereinstimmung enthält

12

Ich versuche, eine Protokolldatei nach protokollierten Aktivitäten zu durchsuchen, die nicht abgeschlossen wurden. Zum Beispiel protokolliere ich eine "Startaktivität für ID 1234 ..." und bei Erfolg lautet die nächste Zeile "Aktivität 1234 abgeschlossen".

Ich versuche, die Zeilen "Starting ..." abzurufen, denen NICHT die entsprechenden Zeilen "Completed" folgen.

Beispielprotokolldatei

Starting activity for ID 1234
ID 1234 completed successfully
Starting activity for ID 3423
ID 3423 completed successfully
Starting activity for ID 9876
ID 9876 completed successfully
Starting activity for ID 99889
ID 99889 completed successfully
Starting activity for ID 10011
ID 10011 completed successfully
Starting activity for ID 33367
Starting activity for ID 936819
ID 936819 completed successfully

In diesem Beispiel würde ich nach der Ausgabe suchen:

Starting activity for ID 33367

... weil es keine "abgeschlossene" Zeile gibt.

Ich habe versucht, dies mit grepund zu tun awk, hatte aber nicht viel Erfolg. Ich gehe davon aus, dass dies mit einem dieser Tools möglich ist, aber my grepund awkchops sind nicht fortgeschritten.

Suchen Sie eine schnelle und zuverlässige grepoder awkMuster , die Ergebnisse zu geben , die ich hier brauchen.

PattMauler
quelle
Ich denke, mit grep + awk ist es nicht einfach, aber können Sie ein wenig erklären, warum Sie das tun? Eine Ausgabe aller laufenden Aktivitäten, zB Erfolg oder nicht abgeschlossen?
Gänseblümchen
@ warl0ck, ich suche das "nicht fertig".
PattMauler

Antworten:

10

Hier ist eine awkAlternative:

awk '
  /^Starting/ { I[$5] = $0                  }
  /^ID/       { delete I[$2]                }
  END         { for (key in I) print I[key] }
' infile

Ausgabe:

Starting activity for ID 33367

Das Iassoziative Array verfolgt, welche IDs gesehen wurden.

Thor
quelle
Dies funktioniert sehr gut, da es sogar Situationen zu bieten scheint, in denen die Protokollzeilen "Starting ..." und "Completed ..." nicht benachbart / sequentiell sind. Vielen Dank @Thor!
PattMauler
Gern geschehen. Dies sollte bei (fast) beliebiger Größeneingabe effizient funktionieren, da nur die ID gespeichert wird und die Nachschlagezeit 0 (1) ist.
Thor
Nett. Nur eins: Wie ich von @RobertL ( unix.stackexchange.com/a/243550/135943 ) erfahren habe, müssen Sie keinen Wert zuweisen, um ein Array-Element zu erstellen. I[$5] = 1Sie können also stattdessen einfach verwenden I[$5]. (Sie interessieren sich nicht für den Wert, Sie möchten nur das Element vorhanden machen , und durch einfaches Benennen wird dies erreicht.)
Platzhalter
@Wildcard: Sie haben Recht, aber nach Durchsicht der Frage des OP und der grep-ähnlichen Ausgabe, nach der er sucht, ist es sinnvoller, sich an die gesamte Zeile zu erinnern und diese am Ende auszugeben.
Thor
3
sed '$!N;/\n.*completed/d;P;D' <input

Dies wird von dem Ausgang alle Eingabezeilen löschen , die durch eine Linie nicht gefolgt passen die Zeichenfolge abgeschlossen .

mikeserv
quelle
2

So können Sie es mit GNU sed machen:

sed -r 'N; /([0-9]+)\n\w+\s+\1/d; P; D' infile
  • N Liest eine weitere Zeile in den Musterraum.
  • Der Match-Regex prüft, ob identische IDs gefunden wurden. In diesem Fall wird der Musterbereich gelöscht ( d) und der Zyklus neu gestartet.
  • Wenn es nicht übereinstimmt, drucken Sie die erste Zeile im Musterbereich aus ( P) und löschen Sie sie ( D).
Thor
quelle
Ich kann hier nichts Verlängertes sehen ... also -rwird es nicht benötigt, oder?
Louis Maddox
1
@lmmx: Dies wird benötigt, da ansonsten die Erfassungsgruppe maskiert werden muss, und dasselbe gilt für den +Quantifizierer.
Thor
Ach ok Ich änderte es und wurde gesagt, dass es nicht notwendig ist, danke für die Klärung
Louis Maddox
1

Wenn Ihre Installation pcregrep unterstützt, ist die Option "Multiline (-M)" hilfreich.

pcregrep -M -o '\AStarting activity for ID (\d+)\n(?!ID \1)' t.z

Startaktivität für ID 33367

iruvar
quelle