Wie lese ich bestimmte Zeilen, nachdem ich einen Text gefunden habe?

12

Wie kann ich eine bestimmte Anzahl von Zeilen lesen, nachdem ich Text gefunden habe?

Z.B.:

Lesen Sie die nächsten 2 Zeilen, nachdem Sie "Unix" gefunden haben:

Test 1
Test 2
Test 3
Test 4
UNIX
Test 5
Test 6
Test 7
Test 8
Test 9

Ergebnis kann sein:

Test 5
Test 6

Hinweis: Das "Unix" im letzten Beispiel ist ein Argument und kann daher ein beliebiger anderer Text sein.

Was ich habe:

Ich habe immer noch keine Ideen mehr, brauche nur ein Licht. Denken Sie daran, ein anderes Skript zu erstellen, um dies zu tun.

Kalt
quelle

Antworten:

10

Eine awkLösung:

$ awk '$0 == "UNIX" {i=1;next};i && i++ <= 2' file
Test 5
Test 6

Erläuterung

  • /^UNIX$/{i=1;next}: Wenn wir sehen UNIX, setzen wir die Variable i = 1und verarbeiten sie zur nächsten Eingabe.

  • Wenn die Variable igesetzt ist (was bedeutet, dass wir sie gesehen haben UNIX), wird sie i && i++ <= 2erst in den nächsten zwei Zeilen auf den wahren Wert ausgewertet UNIX, was zu einer awkausgeführten Standardaktion führt print $0.

  • Vor sieht UNIX, iwurde in der 3. Zeile nicht definiert und beginnen nach UNIX, ieinen Wert von mehr als 2 hatte, die die Expression machen i && i++ <= 2zu falsch ausgewertet, was awknichts zu tun.

cuonglm
quelle
Nach dem Test Ihrer Lösung erhalte ich diese Fehlermeldung: Fehlersystax in der Nähe von Zeile 1 Rettung in der Nähe von Zeile 1
Cold
@Cold: Was bist du gelaufen? Bitte beachten Sie, dass das $Zeichen am Anfang meiner Antwort eine Shell-Eingabeaufforderung ist und nicht Teil des awkBefehls.
Cuonglm
Eine andere Variante:awk '/^UNIX$/ {s=NR;next} s && NR<=s+2'
Musiphil
Ich weiß, dass @cuonglm
Cold
@Cold: Was ist dein Betriebssystem?
Cuonglm
12

Eine grepLösung:

grep -A2 -P '^UNIX$' file

Erläuterung: -A bedeutet: Drucken Sie die nächsten beiden Zeilen nach dem Spiel aus

Oder awk:

awk '$0=="UNIX"{getline; print; getline; print}' file

Erläuterung: Diese Anweisung sucht in line ( $0=="UNIX") nach UNIX . Wenn das gegeben ist, bekommt es den nächsten in seinen buffer ( getline) und druckt den buffer ( print). Dies wird zweimal durchgeführt.

Oder verwenden Sie sed:

sed -n '/^UNIX$/{n;p;n;p}' file

Erläuterung: Das sucht nach UNIX ( /^UNIX$/). Wenn dies gefunden wird, wird das Teil in der Datei ausgeführt {...}. nbedeutet weiter, pbedeutet drucken. Dies geschieht ebenfalls doppelt so häufig.

Chaos
quelle
Danke @chaos, ich werde die letzten 2 Optionen ausprobieren, die du gibst. Bitte fügen Sie eine Erklärung zu jeder Option bei, ich werde sie nicht verstehen und tun.
Kalt
Wenn sich die Anzahl der Zeilen ändert, wie viele Änderungen werde ich an den letzten beiden Optionen vornehmen? Danke
Kalt
@ Kalt siehe meine Bearbeitung. So ändern Sie die Anzahl, wenn Zeilen den getline; print;Teil in der awkAnweisung oder den n;p;Teil in der sedAnweisung wiederholen .
Chaos
Danke @chaos, aber je höher die Anzahl der Zeilen, desto größer der Ausdruck und die Änderung ist meiner Meinung nach nicht durchführbar. Denkst du nicht? Wenn 100 Zeilen?
Kalter
@Cold Dann würde ich die grep-Lösung mit verwenden grep -A100 -P '^UNIX$' file | tail -n +2. Der Endteil besteht darin, das erste Pfandrecht zu entfernen. In den anderen (sed, awk) müssten Sie Schleifen schreiben, was es weniger einfach macht.
Chaos
4
grep -A 2 UNIX file.txt

Die Manpage von grep beschreibt die Option folgendermaßen:

  -A NUM, --after-context=NUM
      Print NUM  lines  of  trailing  context  after  matching  lines.
      Places  a  line  containing  --  between  contiguous  groups  of
      matches.
Funkeln
quelle
Hallo @Twinkles, gute Antwort, aber mein grep hat nur diese Optionen "hblcnsviw". Aber die Logik ist gut. danke
kalt
Dies wird auch UNIXin der Ausgabe gedruckt .
Cuonglm
Um das wegzulassen UNIX, leiten Sie es an tail: [...] | tail -n +1oder an sed: [...] | sed '1d'.
DopeGhoti
1
@DopeGhoti: Ihre tailund sed '1d'Vorschläge funktionieren nur dann korrekt, wenn sie UNIXnur einmal im Eingabetext erscheinen. Alle anderen Antworten ermöglichen mehrere Vorkommen. Es könnte besser sein, vorzuschlagen ... | grep -v UNIX. Zugegeben, dies wird chaotisch, wenn es UNIXin den Zeilen 15 und 17 erscheint.
G-Man sagt 'Reinstate Monica'
Gute Argumente. Ich bin mir ziemlich sicher, dass es einfach sedmit irgendeiner Form geschehen könnte sed '/UNIX/d;n;n;p/' /path/to/file, die ich gerade herausgearbeitet und als Antwort eingereicht habe.
DopeGhoti
0

Dies scheint den Trick gut zu machen:

sed -n '/UNIX/{n;p;n;p}' /path/to/file

Konzeptioneller Beweiß:

$ for i in {1..9}; do echo $i; done | sed -n '/4/{n;p;n;p}'
5
6
DopeGhoti
quelle
1
Die Unterschale um Ihre forSchleife ist nicht erforderlich.
Bis auf weiteres angehalten.
In der Tat ist es nicht; Es war ein Überbleibsel einer anderen Fafferie, in der ich mich früher am Tag mitten auf dieser Muschel befand. Parens entfernt.
DopeGhoti
0

Sie können verwenden ex:

ex -s +'1,/UNIX/d|%p|q!' file_or_/dev/stdin

wo:

  • 1,/UNIX/d- Entfernt Text nach dem Match
  • %p - druckt Puffer
  • q!- Beenden, ohne Änderungen an der Datei zu speichern ( wqzum Bearbeiten an Ort und Stelle verwenden)
Kenorb
quelle