it-swarm.com.de

Grep eine Protokolldatei für das letzte Vorkommen einer Zeichenfolge zwischen zwei Zeichenfolgen

Ich habe eine Protokolldatei trace.log. Darin muss ich den Inhalt der Zeichenfolgen <tag> und </tag> angeben. Es gibt mehrere Sätze dieses Zeichenkettenpaares, und ich muss nur den Inhalt zwischen dem letzten Satz zurückgeben (mit anderen Worten, aus der Variablen tail der Protokolldatei).

Extra Credit: Kann ich den Inhalt der beiden Zeichenfolgen nur zurückgeben, wenn der Inhalt "testString" enthält? 

Danke fürs schauen.

BEARBEITEN: Die Suchparameter und sind in verschiedenen Zeilen mit ungefähr 100 Inhaltszeilen enthalten. Der Inhalt ist was ich will ...

24
rs79

Verwenden Sie tac, um die Datei in die andere Richtung zu drucken, und anschließend grep -m1, um nur ein Ergebnis zu drucken. Beim Hinschauen und Vorausschauen wird der Text zwischen <tag> und </tag> überprüft.

tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'

Prüfung

Gegeben diese Datei

$ cat a
<tag> and </tag>
aaa <tag> and <b> other things </tag>
adsaad <tag>and  last one</tag>

$ tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'
and  last one

Aktualisieren

BEARBEITEN: Die Suchparameter und sind in verschiedenen Zeilen mit .__ enthalten. ungefähr 100 Zeilen Inhalt, die sie trennen. Der Inhalt ist was ich bin nach dem...

Dann ist es etwas kniffliger:

tac file | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]};
                /<tag>/   {p=0; split($0, a, "<tag>");  $0=a[2]; print; exit};
                p' | tac

Die Idee ist, die Datei umzukehren und ein Flag p zu verwenden, um zu prüfen, ob der <tag> bereits erschienen ist oder nicht. Der Druckvorgang wird gestartet, wenn </tag> angezeigt wird, und endet, wenn <tag> erscheint (weil wir umgekehrt lesen).

  • split($0, a, "</tag>"); $0=a[1]; erhält die Daten vor </tag>
  • split($0, a, "<tag>" ); $0=a[2]; erhält die Daten nach <tag>

Prüfung

Gegeben eine Datei a wie folgt:

<tag> and </tag>
aaa <tag> and <b> other thing
come here
and here </tag>

some text<tag>tag is starting here
blabla
and ends here</tag>

Die Ausgabe wird sein:

$ tac a | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]}; /<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit}; p' | tac
tag is starting here
blabla
and ends here
33
fedorqui

Wenn Sie wie ich, haben Sie keinen Zugang zu tac, weil Ihr Sysadmin keinen Ball spielt. Sie können es versuchen:

grep pattern file | tail -1
22
SlackGadget

Eine andere Lösung als grep wäre sed:

tac file | sed -n '0,/<tag>\(.*\)<\/tag>/s//\1/p'

tac file druckt die Datei in umgekehrter Reihenfolge (cat rückwärts), dann geht sed von der Eingabezeile 0 zum ersten Vorkommen von <tag>.*<\tag> über und ersetzt <tag>.*<\tag> nur durch den Teil, der sich in <tag> befand. Das Flag p gibt die Ausgabe aus, die von -n unterdrückt wurde.

Bearbeiten: Dies funktioniert nicht, wenn sich <tag> und </tag> in unterschiedlichen Zeilen befinden. Wir können sed noch dafür verwenden:

tac file | sed -n '/<\/tag>/,$p; /<tag>/q' | sed 's/.*<tag>//; s/<\/tag>.*//' | tac

Wieder verwenden wir tac, um die Datei rückwärts zu lesen. Dann liest der erste sed-Befehl das erste Vorkommen von und wird beendet, wenn er gefunden wird. Nur die Zeilen dazwischen werden gedruckt. Dann geben wir es an einen anderen sed-Prozess weiter, um die Zeilen zu entfernen und die Zeilen schließlich mit tac wieder umzukehren.

1
pfnuesel
Perl -e '$/=undef; $f=<>; Push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1]' ex.txt

Extra Credit: Auf jede Art und Weise kann ich den Inhalt von .__ zurückgeben. nur zwei Strings, wenn der Inhalt "testString" enthält?

Perl -e '$/=undef; $f=<>; Push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1] if ($a[-1]~=/teststring/);' ex.txt
0
Vorsprung

Ein kleines ungeprüftes awk, das mehrere Zeilen verarbeitet:

awk '
    BEGIN    {retain="false"}
    /<\tag>/ {retain = retain + $0; keep="false"; next}
    /<tag>/  {keep = "true"; retain = $0; next}
    keep == "true" {retain = retain + $0}
    END {print retain}
' filename

Wir beginnen nur die Datei zu lesen; Wenn wir das treffen, beginnen wir, Linien zu halten. Wenn wir das treffen, hören wir auf. Wenn wir eine andere treffen, löschen wir die zurückbehaltene Zeichenfolge und beginnen erneut. Wenn Sie alle Zeichenfolgen haben möchten, drucken Sie bei jeder 

0
mpez0