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.

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.


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.


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.

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

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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.