Auswählen des ersten Auftretens zwischen zwei Mustern, die diese enthalten


27

Wie kann ich das erste Vorkommen zwischen zwei Mustern einschließlich auswählen? Vorzugsweise mit sedoder awk.

Ich habe:

text
something P1 something
content1
content2
something P2 something
text
something P1 something
content3
content4
something P2 something
text

Ich möchte das erste Auftreten der Linien zwischen P1 und P2 (einschließlich P1-Linie und P2-Linie):

something P1 something
content1
content2
something P2 something

Antworten:


22
sed '/P1/,/P2/!d;/P2/q'

... derledigt die Aufgabe portabel, indem alle Zeilen, die !nicht in den Bereich fallen, qgelöscht werden und beim ersten Mal das Ende des Bereichs erreicht wird. Es schlägt für P2 vor P1 nicht fehl, und es erfordert keine GNU-spezifische Syntax, um einfach zu schreiben.


Ausgezeichnet! Viel besser als meins.
muru

1
@muru - Es ist oft einfacher, Verzerrungen zu vermeiden, wenn Sie versuchen, den Autoprint zu verwenden - lassen Sie den Zyklus für Sie arbeiten. Das ist die Gewohnheit, in die ich sowieso gefallen bin. Ich denke, es wird wahrscheinlich am besten als ein Schnitt gegen eine ausgewählte Methode beschrieben - ich neige dazu, ein Muster zu negieren, anstatt danach zu suchen.
mikeserv

Dies hängt bei der Verarbeitung großer Dateigrößen.
Brain90

@ Brain90 - sollte nicht. Wenn Sie Ihre Beschwerde zuverlässig reproduzieren können, wenden Sie sich an den Betreuer Ihrer sed... das ist ein Fehler sed, der nicht im obigen Skript enthalten ist.
mikeserv

1
@mikeserv Ich hätte es nicht gesagt, wenn ich nicht wäre. Ihre Besorgnis darüber, ob ich ein paar Charaktere mag oder nicht, ist seltsam: Ich habe festgestellt, dass der sed-Ausdruck /P2/qauf meinem System sowohl mit als auch ohne funktioniert; das ist es. Ich war neugierig auf etwas und wollte mitteilen, was ich gefunden habe.
Alexej Magura

8

mit awk

awk '/P1/{a=1};a;/P2/{exit}' file
something P1 something
content1
content2
something P2 something

8

In sed:

sed -n '/P1/,/P2/p; /P2/q'
  • -nunterdrückt den Standarddruck und Sie drucken mit dem pBefehl Zeilen zwischen den übereinstimmenden Adressbereichen .
  • Normalerweise würde dies mit beiden Abschnitten übereinstimmen, sodass Sie ( q) beenden, wenn die erste P2Übereinstimmung vorliegt.

Dies wird scheitern, wenn ein vor P2kommt P1. Um diesen Fall zu behandeln, versuchen Sie:

sed -n '/P1/,/P2/{p; /P2/q}'

1
Ich stimme dir nicht zu; Die Antwort von mikeserv ist nicht besser als deine.
G-Man sagt, dass Monica

@ g-man - pshaw. aber ich dachte nur das gleiche.
mikeserv

1
@ gman - nein. jetzt habe ich es verstanden. Minen viel besser. nein {stack}!
mikeserv

1

Wenn Sie die Muster selbst überspringen möchten, finden Sie hier die awkVersion:

awk '/P2/ {exit} /P1/ {f=1; next} f' file

Funktioniert bei mir. Können Sie weitere Informationen zur Funktionsweise des Befehls hinzufügen?
0xAffe

1

Eine einfachere awkLösung (auf halbem Weg zwischen Iruvars Antwort und  Murus Antwort , aber ohne Verwendung einer Variablen):

awk '/P1/,/P2/ { print }  /P2/ { exit }'

und, wie muru bemerkte, wenn das erste P2 vor dem ersten P1 erscheint, druckt dies nichts.

Natürlich, wenn Sie alle P1-P2-Bereiche drucken möchten:

something P1 something
content1
content2
something P2 something
something P1 something
content3
content4
something P2 something

Lass einfach das exitTeil weg :

awk '/P1/,/P2/ { print }'

1
awk '/P1/,/P2/{print;f=1} f&&/P2/{exit}' data

Beenden Sie sofort nach dem Drucken, nicht vorher.


0

So überspringen Sie die Muster selbst und zeigen nur den ersten passenden Block in einer einzelnen GNU sed an:

sed -nre '/STARTPATTERN/ {:a;n;/ENDPATTERN/{b;};p;ba}' file
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.