Wie drucke ich alle Zeilen nach einer Übereinstimmung bis zum Ende der Datei?


48

Eingabedatei1 ist:

dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Ich gebe dem Match das Muster aus in other file(wie dog 123 4335aus file2).

Ich stimme mit dem Muster der Linie überein dog 123 4335und nachdem ich alle Linien ohne Übereinstimmungslinie gedruckt habe, ist meine Ausgabe:

cat 13123 23424
deer 2131 213132
bear 2313 21313

Wenn Sie nur ohne Adresse der Zeile verwenden, verwenden Sie nur das Muster, z. B. 1s wie Sie die Zeilen abgleichen und drucken?


Kann eine andere Datei nur ein einziges zu suchendes Muster oder ein Muster pro Zeile enthalten und die Suche an derjenigen Zeile beginnen, die zuerst in der gesuchten Datei gefunden wurde?
Ciro Santilli

Antworten:


27

Angenommen, Sie möchten mit GNU die gesamte Zeile mit Ihrem Muster abgleichen sed:

sed -n '/^dog 123 4335$/ { :a; n; p; ba; }' infile

Standardäquivalent:

sed -ne '/^dog 123 4335$/{:a' -e 'n;p;ba' -e '}' infile

Mit folgender Eingabe ( infile):

cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Die Ausgabe ist:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

Erläuterung:

  • /^dog 123 4335$/ Sucht nach dem gewünschten Muster.
  • :a; n; p; ba;ist eine Schleife, die eine neue Zeile von input ( n) abruft, sie druckt ( p) und zu label a zurückverzweigt :a; ...; ba;.

Aktualisieren

Hier ist eine Antwort, die Ihren Anforderungen näher kommt, dh Muster in Datei2, das von Datei1 abweicht:

tail -n +$(( 1 + $(grep -m1 -n -f file2 file1 | cut -d: -f1) )) file1

Das eingebettete grep und cut findet die erste Zeile, die ein Muster aus file2 enthält, diese Zeilennummer plus eins wird an tail weitergereicht, die plus eins ist dazu da, die Zeile mit dem Muster zu überspringen.

Wenn Sie mit dem letzten Spiel anstelle des ersten Spiels beginnen möchten, wäre dies:

tail -n +$(( 1 + $(grep -n -f file2 file1 | tail -n1 | cut -d: -f1) )) file1

Beachten Sie, dass nicht alle Versionen von tail die Plus-Notation unterstützen.


Dies ist das erste Beispiel für die Befehle n und p in sed, das ich gesehen habe und bei dem es nicht so aussieht, als würde man sed zu weit gehen. Es scheint (aus meinen kurzen Tests), dass sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(mit vertauschtem p und n) auch die übereinstimmende Zeile erfolgreich eingeschlossen wird.
Josiah Yoder

26

Wenn Sie eine einigermaßen kurze Datei grephaben, könnte dies funktionieren:

grep -A5000 -m1 -e 'dog 123 4335' animals.txt

5000 ist meiner Meinung nach "ziemlich kurz", da es grepdie erste Übereinstimmung findet und zusammen mit den nächsten 5000 Zeilen ausgibt (die Datei muss nicht so viele enthalten). Wenn Sie das Streichholz selbst nicht wollen, müssen Sie es abschneiden, z

grep -A5000 -m1 -e 'dog 123 4335' animals.txt | tail -n+2


Wenn Sie nicht die erste, sondern die letzte Übereinstimmung als Trennzeichen wünschen, können Sie dies verwenden:

tac animals.txt | sed -e '/dog 123 4335/q' | tac

Diese Zeile liest animals.txtin umgekehrter Reihenfolge von Zeilen und Ausgaben bis einschließlich der Zeile mit dog 123 4335und kehrt dann wieder um, um die richtige Reihenfolge wiederherzustellen.

Wenn Sie die Übereinstimmung im Ergebnis nicht benötigen, hängen Sie den Schwanz an. (Sie können den sed-Ausdruck auch komplizieren, um den Puffer vor dem Beenden zu verwerfen.)


Nach meinem Test gibt GNU grep 3.0 im Nachkontext nicht mehr als 132 Zeilen aus (unabhängig vom angegebenen Wert).
Ruvim

22

In der Praxis würde ich wahrscheinlich die meiste Zeit Aet3miirahs Antwort verwenden, und Alexeys Antwort ist wunderbar, wenn ich durch die Zeilen navigieren möchte (auch, es funktioniert auch mit less). OTOH, ich mag wirklich einen anderen Ansatz (der eine Art der umgekehrten Antwort von Gilles ist :

sed -n '/dog 123 4335/,$p'

Beim Aufrufen mit dem -nFlag werden seddie von ihm verarbeiteten Zeilen standardmäßig nicht mehr gedruckt. Dann verwenden wir ein 2-Adressen-Formular, das besagt, dass ein Befehl von der übereinstimmenden Zeile /dog 123 4335/bis zum Ende der Datei (dargestellt durch $) angewendet werden soll . Es handelt sich um den Befehl p, der die aktuelle Zeile ausgibt. Das bedeutet also "Drucke alle Zeilen von der einen /dog 123 4335/bis zum Ende."


3
Dadurch wird die dogZeile gedruckt , die hier nicht gewünscht ist.
Stéphane Chazelas

1
Dies sieht wie die beste Antwort aus (und funktioniert für meinen eigenen Fall), müsste aber angepasst werden, um auch die übereinstimmende Zeile zu überspringen.
Pavel Šimerda

1
sed -n '/ dog 123 4335 /, $ p' | sed '1d' wird die Hundeleine entfernen
Kemin Zhou

1
sed -n '/dog 123 4335/,$p' | tail -n +2wird das Spiel auch entfernen
Gilad Mayani

15
sed -e '1,/dog 123 4335/d' file1

Wenn Sie das Muster aus einer Datei lesen müssen, setzen Sie es in den Befehl sed ein. Wenn die Datei ein Sed-Muster enthält:

sed -e "1,/$(cat file2)/d" file1

Wenn die Datei eine zu suchende Literalzeichenfolge enthält, setzen Sie alle Sonderzeichen in Anführungszeichen. Ich gehe davon aus, dass die Datei eine einzelne Zeile enthält.

sed -e "1,/$(sed 's/[][\\\/^$.*]/\\&/g' file2)/d" file1

Wenn Sie möchten, dass die Übereinstimmung die gesamte Zeile und nicht nur eine Teilzeichenfolge ist, wickeln Sie das Muster ein ^…$.

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1

6
Das funktioniert nicht, wenn sich das Muster in der ersten Zeile befindet. GNU sedhat 0,/dog.../ddafür.
Stéphane Chazelas

14

$ more +/"dog 123 4335" file1


4
Es funktioniert auch mit less.
Brandizzi

3
klug auf dem Terminal, aber es funktioniert nicht wirklich, wenn Sie es in etwas anderes wie Pipe tac.
jcomeau_ictx

Ich benutze es so, $ mehr + / "Match my Words" Datei1 >> Datei2
AMB

1
Möglicherweise +wurde durch -pin POSIX 7 ersetzt: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html, aber noch nicht in util-linux 2.20.1 implementiert. Und dies auch druckt skipping..und einige zusätzliche Zeilen (zu stderr ich denke, so könnte in Ordnung sein).
Ciro Santilli

Vielleicht haben sich die Dinge seitdem geändert? Mein Kommentar erhielt 3 positive Stimmen, so dass es zu der Zeit relevant gewesen sein könnte ...
jcomeau_ictx

11

Mit awk:

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"

5

Ein Weg mit awk:

awk 'NR==FNR{a[$0];next}f;($0 in a){f=1}'  file2 file1

Wobei file2 Ihre Suchmuster enthält. Zunächst wird der gesamte Inhalt von Datei2 im Array "a" gespeichert. Wenn die Datei1 verarbeitet wird, wird jede Zeile mit dem Array verglichen und nur gedruckt, wenn sie nicht vorhanden ist.


Ich denke, das OP möchte jede Zeile nach dem Muster ausgeben.
Thor

@Thor: Danke für den Hinweis, aktualisiert es jetzt ...
Guru

Schön gemacht :).
Thor

5

Wenn die Eingabe eine suchbare reguläre Datei ist:

Mit GNU grep:

{ grep  -xFm1 'dog 123 4335' >&2
  cat; } <infile 2>/dev/null >outfile

Mit sed:

{ sed -n '/^dog 123 4335$/q'
  cat; } <infile >outfile

Eine GNU mit dem grepNamen w / the -moption beendet die Eingabe bei der Übereinstimmung und verlässt die (suchbare) Eingabe fd unmittelbar nach dem Punkt, an dem sie die letzte Übereinstimmung gefunden hat. Wenn Sie also grepw / aufrufen, wird -m1das erste Vorkommen eines Musters in einer Datei gefunden, und der Eingabeversatz wird genau an der richtigen Stelle catbelassen, damit nach der ersten Übereinstimmung des Musters in einer Datei mit stdout alles geschrieben werden kann.

Auch ohne eine GNU grepkönnen Sie genau dasselbe mit einer POSIX-kompatiblen tun sed- wenn sed quits angegeben ist, wird der Eingabeversatz dort belassen, wo er ist. GNU sedist auf diese Weise jedoch nicht standardkonform und daher funktioniert das oben Genannte wahrscheinlich nicht mit GNU, es sedsei denn, Sie rufen es mit seinem -uSchalter auf.


Es ist zu beachten, dass die sedhier gezeigte Stream-Freigabe nicht speziell (obwohl der hier angegebene Standard speziell sedals ein Dienstprogramm bezeichnet wird, das auf diese Weise in der Lage ist) für den gezeigten freien und bedingt kooperativen Workflow ist. Insbesondere sind alle Standarddienstprogramme dafür vorgesehen und spezifiziert, auf diese Weise zusammenzuarbeiten und Cursorpositionen von Eingabeströmen gemeinsam zu nutzen, ohne dass der nächste Leser irgendeine Verarbeitung versäumt. grep -qsollte dies tun; quietly grepsollte zurückkehren, sobald eine Übereinstimmung in der Eingabe gefunden wird, und alle verbleibenden Eingaben sollten standardmäßig nicht verbraucht werden.
mikeserv

4

Meine Antwort auf die Frage im Betreff, ohne Muster in einer zweiten Datei zu speichern. Hier ist meine Testdatei:

$ cat animals.txt 
cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

GNU sed:

 $ sed '0,/^dog 123 4335$/d' animals.txt 
 cat 13123 23424 
 deer 2131 213132
 bear 2313 21313

Perl:

$ perl -ne 'print unless 1.../^dog 123 4335$/' animals.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Perl-Variante mit Muster in einer Datei:

$ cat pattern.txt 
dog 123 4335
$ perl -ne 'BEGIN{chomp($p=(<STDIN>)[0])};print unless 1../$p/;' animals.txt < pattern.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

2

Mit ed:

ed -s file1 <<< '/dog 123 4335/+1,$p'

Dies sendet einen print-Befehl an ed in einem Here-String. Der Druckbefehl ist in seinem Bereich auf eins nach ( +1) der dog 123 4335Übereinstimmung bis zum Ende der Datei ( $) beschränkt.


1

Wenn Ihnen die Erstellung einer temporären Datei nichts ausmacht und csplitverfügbar ist, funktioniert Folgendes:

sh -c 'csplit -sf"$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

Hinweis file1ist die Eingabedatei und file2ist die Musterdatei (wie in der Frage angegeben).

Die lange Form des obigen Befehls lautet:

sh -c 'csplit --quiet --prefix="$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

dh

csplit --quiet --prefix="file1_" "file1" "%^$(cat "file2")%+1" && cat "file1_00"

csplitohne das prefixobige Flag würde die Datei erstellt xx00(Präfix xxund Suffix 00). Mit der Flagge oben wird die Datei erstellt file1_00. Ohne das quietFlag wird die Ausgabedateigröße (Größe der resultierenden Datei) gedruckt.


0

Da awk nicht ausdrücklich abgelehnt wird, gehe ich davon aus, dass "cat" das Match ist.

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt

0

Wie drucke ich alle Zeilen nach einer Übereinstimmung bis zum Ende der Datei?

Ein anderer Weg, es sedauszudrücken, ist "wie man alle Zeilen von der ersten bis zur Übereinstimmung (einschließlich) löscht ", und dies kann geschrieben werden als:

sed -e '1,/MATCH PATTERN/d'

1
Das einzige Problem ist, wenn das Muster in der ersten Zeile steht ...
don_crissti

1
Unterscheidet sich das von unix.stackexchange.com/a/56517/32558 ?
Ciro Santilli

Ich denke, wir brauchen hier ein Komitee, um zu entscheiden.
Poige

1
@poige: nee, du gibst die selbe antwort weniger umfassend
thor

@don_crissti, was ist sed -e '0,/MATCH PATTERN/d'dann?
Velkan
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.