
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 Variable
f
wahr (ungleich Null) ist, dann füge die aktuelle Zeile an das Ende der Variable ana
./Condition 1/{a=$0; f=1}
Wenn die aktuelle Zeile enthält
Condition 1
, dann setzes
auf die aktuelle Zeile setzen und die Variablef
auf 1 setzen.f && /Condition 2/{print a; f=0}
Wenn
f
wahr ist und die aktuelle Zeile enthältCondition 2
, dann Variable druckena
und 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 vi
dem unmittelbaren Vorgänger) – sehr flexibel.
printf '%s\n' 'g/Condition 2/?Condition 1?,.p' | ex output.out
Das heisst:
Für jede Zeile ( g
global), die dem Muster "Bedingung 2" entspricht, suchen Sie rückwärts nach der unmittelbar vorhergehenden Instanz von "Bedingung 1" und p
drucken 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_2
mindestens eine übereinstimmende Zeile vorangeht PATTERN_1
. Für den allgemeineren Fall fügen Sie eine weitere Bedingung hinzu, um PATTERN_1
vor 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
-0777
und-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
).