Druckbereiche vom letzten Vorkommen eines bestimmten Musters bis zum ersten Vorkommen eines anderen Musters

Druckbereiche vom letzten Vorkommen eines bestimmten Musters bis zum ersten Vorkommen eines anderen Musters

Guten Morgen, das ist der Frage sehr ähnlichGrep vom letzten Vorkommen eines Musters zu einem anderen Muster(mehrere Monate alt), wobei ein paar weitere Details hinzugefügt wurden.

Ich versuche, ein UNIX-Skript für eine Datei mit mehreren doppelten Mustern zu schreiben, gefolgt von dem Muster, nach dem ich suche. Ich habe jedoch weder „tac“ noch „tail -r“ (mit dem UNIX-Emulator MKS Toolkit) und möchte das letzte Vorkommen von Muster1 vor Muster2 zurückgeben, gefolgt von den Daten zwischen Muster1 und Muster2 und dann auch Muster2. Die Muster wären in diesem Fall „Bedingung 1“ und „Bedingung 2“:

Ausgabe.out:

...
Condition 1: A
data1
Condition 1: B
data2
Condition 2: C
data3
Condition 1: D
data4
Condition 1: E
data5
Condition 2: F
...

Ich möchte ein awk-Skript (oder ein sed-Skript, aber ich dachte, awk wäre das richtige Tool) schreiben, um Folgendes zurückzugeben:

Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F

Ich nehme an, dass es sich um eine Form der folgenden Zeile handelt, aber ich bekomme die Syntax nicht hin:

awk '/Condition 1/ {acc = $0;} /,/Condition 2/ {print ?}' output.out

Bei der Arbeit mit '/,/' scheine ich Probleme zu haben. Ich habe mich gefragt, ob jemand einen Rat hat, ich wäre sehr dankbar. Vielen Dank für jede Hilfe und Zeit im Zusammenhang mit dieser Frage.

Antwort1

Versuchen:

$ awk 'f{a=a"\n"$0} /Condition 1/{a=$0; f=1} f && /Condition 2/{print a; f=0}' output.out 
Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F

Wie es funktioniert

  • f{a=a"\n"$0}

    Wenn die Variablef wahr (ungleich Null) ist, dann füge die aktuelle Zeile an das Ende der Variable an a.

  • /Condition 1/{a=$0; f=1}

    Wenn die aktuelle Zeile enthält Condition 1, dann setzes auf die aktuelle Zeile setzen und die Variable fauf 1 setzen.

  • f && /Condition 2/{print a; f=0}

    Wenn fwahr ist und die aktuelle Zeile enthält Condition 2, dann Variable drucken aund setzenf auf Null zurückgesetzt.

Antwort2

Wenn Sie eine umgekehrte Adressierung in der Textverarbeitung wünschen, verwenden Sieex

Es istPOSIX spezifiziert, und es ist die skriptfähige Form von vi(und videm unmittelbaren Vorgänger) – sehr flexibel.

printf '%s\n' 'g/Condition 2/?Condition 1?,.p' | ex output.out

Das heisst:

Für jede Zeile ( gglobal), die dem Muster "Bedingung 2" entspricht, suchen Sie rückwärts nach der unmittelbar vorhergehenden Instanz von "Bedingung 1" und pdrucken Sie alle Zeilen von dieser Zeile bis zur aktuellen Zeile (. ) (das ist die Zeile mit „Bedingung 2“).

Die Ausgabe der bereitgestellten Eingabe ist genau so, wie Sie es beschreiben.

Antwort3

sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x' infile

Dies setzt allerdings voraus, dass jeder übereinstimmenden Zeile PATTERN_2mindestens eine übereinstimmende Zeile vorangeht PATTERN_1. Für den allgemeineren Fall fügen Sie eine weitere Bedingung hinzu, um PATTERN_1vor dem Drucken das Vorhandensein im Musterraum zu prüfen:

sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x;/PATTERN_1/!d' infile

Antwort4

Hier ist ein böses Stück Perl:

perl -0777 -ne '
    my $c1 = qr/Condition 1/;
    my $c2 = qr/Condition 2/;
    print for map {s/$c2.*?\n\K.*//s; $_}
              grep {/$c2/}
              split /(?=$c1)/ms;
' output.out

Es:

  • liest die gesamte Datei (mit den Optionen -0777und -n),
  • teilt es dort, wo Bedingung 1 erscheint ( split),
  • filtert Absätze heraus, in denen Bedingung 2 nicht vorkommt ( grep),
  • entfernt dann aus jedem interessanten Absatz alle Zeilen, die auf Zeile „Bedingung 2“ folgen ( map).

verwandte Informationen