Drukuj linię tylko wtedy, gdy następny wiersz NIE zawiera określonego dopasowania

12

Próbuję wyszukać w pliku dziennika zarejestrowane działania, które nie zostały zakończone. Na przykład loguję „Aktywność początkowa dla ID 1234 ...”, a jeśli się powiedzie, w następnym wierszu będzie „Aktywność 1234 zakończona”.

Próbuję uzyskać wiersze „Początek ...”, po których NIE następują odpowiadające im wiersze „Ukończone”.

Przykładowy plik dziennika

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

W tym przykładzie szukałbym danych wyjściowych:

Starting activity for ID 33367

... ponieważ nie następuje po nim wiersz „ukończony”.

Próbowałem robić to z grepa awk, ale nie miał wiele sukcesów. Zakładam, że można to zrobić za pomocą jednego z tych narzędzi, ale moje grepi awkkotlety nie są zaawansowane.

Patrząc na szybkie i niezawodne greplub awkwzoru dać wyniki muszę tutaj.

PattMauler
źródło
Nie sądzę, że jest to łatwe z grep + awk, ale czy możesz wyjaśnić trochę, dlaczego to robisz? Wynik wszystkich bieżących działań, np. Sukces czy nie sfinalizowane?
stokrotka
@ warl0ck, szukam „nieukończonego”.
PattMauler

Odpowiedzi:

10

Oto awkalternatywa:

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

Wynik:

Starting activity for ID 33367

IAsocjacyjna śledzi co identyfikatory zostały zaobserwowane.

Thor
źródło
Działa to naprawdę dobrze, ponieważ wydaje się nawet uwzględniać sytuacje, w których wiersze dziennika „Początek ...” i „Zakończono ...” nie są sąsiadujące / sekwencyjne. Dzięki @Thor!
PattMauler
Proszę bardzo. Powinno to działać efektywnie z (prawie) dowolnym wejściem o rozmiarze, ponieważ zawsze przechowuje tylko identyfikator, a czas wyszukiwania to O (1).
Thor
Ładny. Tylko jedna rzecz: jak dowiedziałem się z @RobertL ( unix.stackexchange.com/a/243550/135943 ), nie musisz przypisywać wartości, aby utworzyć element tablicy. Zamiast tego I[$5] = 1możesz po prostu użyć I[$5]. (Nie zależy ci na wartości, po prostu chcesz, aby element istniał , a wystarczy nazwać go, aby to osiągnąć.)
Wildcard
@Wildcard: Masz rację, ale po zapoznaniu się z pytaniem OP i wyjściem typu grep, którego szuka, bardziej odpowiednie jest zapamiętanie całej linii i wyjścia, które znajdują się na końcu.
Thor
3
sed '$!N;/\n.*completed/d;P;D' <input

Spowoduje to usunięcie z wyjścia wszystkich wierszy wejściowych, po których nie ma wiersza pasującego do zakończonego ciągu .

mikeserv
źródło
2

Oto, jak możesz to zrobić z GNU sed:

sed -r 'N; /([0-9]+)\n\w+\s+\1/d; P; D' infile
  • N wczytuje jeszcze jedną linię do przestrzeni wzorów.
  • Dopasowanie wyrażenia regularnego sprawdza, czy znaleziono identyczne identyfikatory, jeśli więc przestrzeń wzorcowa jest usuwana ( d) i cykl jest restartowany.
  • Jeśli nie pasuje, wydrukuj pierwszy wiersz w przestrzeni wzorca ( P) i usuń go ( D).
Thor
źródło
Nie widzę tu nic przedłużonego ... więc -rnie jest to potrzebne, prawda?
Louis Maddox
1
@lmmx: Jest to potrzebne, ponieważ w przeciwnym razie grupa przechwytywania musi być uciekła, podobnie jest z +kwantyfikatorem.
Thor
Ach OK! Zmodyfikowałem go i powiedziano mi, że nie jest to konieczne, dzięki za wyjaśnienie
Louis Maddox
1

jeśli twoja instalacja obsługuje pcregrep, przydatna jest opcja multiline (-M).

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

Rozpoczęcie aktywności dla ID 33367

iruvar
źródło