
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 line
Ich 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 N
den Wert auf die N-te Zeile vor dem zu druckenden Muster.
Legen Sie pattern
den Wert für den zu suchenden regulären Ausdruck fest.
buffer
ist ein Array von N
Elementen. Es wird zum Speichern der Zeilen verwendet. Jedes Mal, wenn das Muster gefunden wird, N
wird 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 awk
nur 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 PAT
das Muster, das Sie abgleichen möchten, und LIM
die 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-e
auf 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@lines
immer die letztenLIM
Zeilen 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;D
Zyklus – 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
.