Drucken Sie nur die N-te Zeile vor jeder Zeile, die einem Muster entspricht

Drucken Sie nur die N-te Zeile vor jeder Zeile, die einem Muster entspricht

Ich versuche, nur die <N>-te Zeile vor einem Suchmuster zu drucken. grep -B<N>druckt alle <N>Zeilen vor dem Suchmuster. Ich habe den awk-Code gesehenHier<N>das nur die -te Zeile nach dem Suchmuster drucken kann .

awk 'c&&!--c;/pattern/{c=N}' file

<N>Wie kann ich dies ändern, um nur die -te Zeile vor jeder Zeile zu drucken, die übereinstimmt pattern? Hier ist beispielsweise meine Eingabedatei

...
...
   0.50007496  0.42473932  0.01527831
   0.99997456  0.97033575  0.44364198
Direct configuration=     1
   0.16929051  0.16544726  0.16608723
   0.16984300  0.16855274  0.50171112
...
...
   0.50089841  0.42608090  0.01499159
   0.99982054  0.97154975  0.44403547
Direct configuration=     2
   0.16931296  0.16553376  0.16600890
   0.16999941  0.16847055  0.50170694  
...

2nd lineIch brauche einen Befehl, der mir den vor dem Suchstring zurückgibt Direct configuration. Ich versuche, dies in auszuführenSUSE-Linux

Antwort1

Es muss ein Zeilenpuffer verwendet werden.

Probieren Sie Folgendes aus:

awk -v N=4 -v pattern="example.*pattern" '{i=(1+(i%N));if (buffer[i]&& $0 ~ pattern) print buffer[i]; buffer[i]=$0;}' file

Setzen Sie Nden Wert auf die N-te Zeile vor dem zu druckenden Muster.

Legen Sie patternden Wert für den zu suchenden regulären Ausdruck fest.

bufferist ein Array von NElementen. Es wird zum Speichern der Zeilen verwendet. Jedes Mal, wenn das Muster gefunden wird, Nwird die Zeile vor dem Muster gedruckt.

Antwort2

Dieser Code funktioniert nicht für vorherige Zeilen. Um Zeilen vor dem übereinstimmenden Muster zu erhalten, müssen Sie die bereits verarbeiteten Zeilen irgendwie speichern. Da awknur assoziative Arrays vorhanden sind, fällt mir keine ebenso einfache Möglichkeit ein, das zu tun, was Sie in möchten awk, also hier eine Perl-Lösung:

perl -ne 'push @lines,$_; print $lines[0] if /PAT/; shift(@lines) if $.>LIM;' file 

Ändern Sie PATdas Muster, das Sie abgleichen möchten, und LIMdie Anzahl der Zeilen. Um beispielsweise die 5. Zeile vor jedem Vorkommen von auszudrucken foo, führen Sie Folgendes aus:

perl -ne 'push @lines,$_; print $lines[0] if /foo/; shift(@lines) if $.>5;' file 

Erläuterung

  • perl -ne: Lesen Sie die Eingabedatei Zeile für Zeile und wenden Sie das angegebene Skript -eauf jede Zeile an.
  • push @lines,$_: Füge die aktuelle Zeile ( $_) zum Array hinzu @lines.
  • print $lines[0] if /PAT/: Drucken Sie das erste Element im Array @lines( $lines[0]), wenn die aktuelle Zeile dem gewünschten Muster entspricht.
  • shift(@lines) if $.>LIM;: $.ist die aktuelle Zeilennummer. Wenn diese größer als der Grenzwert ist, wird der erste Wert aus dem Array entfernt @lines. Das Ergebnis ist, dass @linesimmer die letzten LIMZeilen vorhanden sind.

Antwort3

tac file | awk 'c&&!--c;/pattern/{c=N}' | tac

Dies weist jedoch dieselben Auslassungen auf wie der Anwendungsfall „Weiterleitungen“, wenn mehrere Übereinstimmungen innerhalb von N Zeilen zueinander vorhanden sind.

Und es funktioniert nicht so gut, wenn die Eingabe von einem laufenden Prozess weitergeleitet wird, aber es ist die einfachste Methode, wenn die Eingabedatei vollständig ist und nicht wächst.

Antwort4

Alternativer Weg mit sed.

FürN = 1:

sed '$!N; /.*\n.*pattern/P; D' FILE

FürN = 2

sed '1N; $!N; /.*\n.*\n.*pattern/P; D' FILE

Für dieN = 2Fall, die erste Zeile wird die nächste lesenN-1Zeilen im Musterbereich, dann starten Sie einen N;P;DZyklus – lesen Sie eine weitere Zeile ein, und wenn die letzte Zeile im Musterbereich übereinstimmt, drucken Sie die erste Zeile im Musterbereich, löschen Sie sie und starten Sie einen neuen Zyklus.

Der Nachteil ist, dass es für verschiedene Werte von geändert werden mussN:

FürN = 3:

sed '1{N;N}; $!N; /.*\n.*\n.*\n.*pattern/P; D' FILE

FürN = 4:

sed '1{N;N;N}; $!N; /.*\n.*\n.*\n.*\n.*pattern/P; D' FILE

so wird es schnell mühsam, aber für größere Werte vonNSie könnten eine Skriptdatei vorbereiten und sie weitergeben an sed.

verwandte Informationen