Entfernen Sie die Zeile mit einer bestimmten Zeichenfolge und der folgenden Zeile

Ich verwende diese

cat foo.txt | sed "/bar/d"

, um Zeilen zu entfernen, die die Zeichenfolge bar in der Datei enthalten.

Ich möchte diese Zeilen und die Zeile jedoch direkt entfernen danach . Vorzugsweise in sed, awk oder einem anderen Tool, das in MinGW32 verfügbar ist.

Es ist eine Art Umkehrung von dem, was ich in grep mit -A und -B erhalten kann, um auch übereinstimmende Zeilen zu drucken als Zeilen vor / nach der übereinstimmenden Zeile.

Gibt es eine einfache Möglichkeit, dies zu erreichen?

Kommentare

  • Nur für Information: Ich ‚ analysiere Protokolle, in denen Einträge zweizeilig sind. Ich möchte also einen Eintrag finden, der zum Muster passt, und ihn sowie die nächste Zeile entfernen. Daher muss ich ‚ keine aufeinanderfolgenden Übereinstimmungszeilen verarbeiten, aber trotzdem danke für die Vollständigkeit Ihrer Antworten!

Answer

Wenn Sie GNU sed haben (also nicht eingebettetes Linux oder Cygwin):

sed "/bar/,+1 d" 

Wenn Sie Wenn bar in zwei aufeinander folgenden Zeilen vorhanden ist, wird die zweite Zeile gelöscht, ohne sie zu analysieren. Wenn Sie beispielsweise eine dreizeilige Datei bar / bar / foo haben, Die Zeile foo bleibt erhalten.

Kommentare

  • +1 für die Länge 🙂 Insbesondere Beispiel Ich habe keine ‚ keine aufeinanderfolgenden bar s, so dass diese sehr einfach zu merken ist.
  • sed '/bar/d', wenn Sie nur “ Zeile mit einer bestimmten Zeichenfolge entfernen möchten “ und nicht das nächste.
  • Wenn ich nach Mathe alle Zeilen entfernen möchte, dann?
  • @Pandya Das ‚ ist anders. Sie können z.B. sed '/math/q'
  • @ A.K. Wenn Sie nur die übereinstimmende Zeile löschen möchten, ist ‚ noch einfacher: sed '/bar/d'

Antwort

Wenn bar in aufeinanderfolgenden Zeilen auftreten kann, können Sie Folgendes tun:

awk "/bar/{n=2}; n {n--; next}; 1" < infile > outfile 

, das angepasst werden kann, um mehr als 2 Zeilen zu löschen, indem die 2 oben mit der Anzahl der zu löschenden Zeilen einschließlich der übereinstimmenden geändert werden.

Wenn nicht, ist dies der Fall „s einfach in sed mit @ MichaelRollins“ -Lösung oder:

sed "/bar/,/^/d" < infile > outfile 

Kommentare

  • Das andere Plus in der AWK-Lösung ist, dass ich /bar/ durch ersetzen kann /bar|baz|whatever/. In sed scheint diese Syntax ‚ nicht zu funktionieren.
  • @ jakub.g, ich habe GNU sed ( v4.4 jetzt). Ich bin mir nicht sicher über die anderen. Was ich weiß ist, dass es “ basic “ Syntax für reguläre Ausdrücke standardmäßig verwendet. Deshalb hat Ihr Beispiel nicht ‚ funktioniert nicht. Um das zu erreichen, was Sie wollen, können Sie entweder einen Backslash vor jede vertikale Linie setzen oder sed bitten, “ extended “ reguläre Ausdrücke. Weitere Informationen finden Sie hier: gnu.org/software/sed/manual/html_node/… . Bitte beachten Sie, dass dies auch für grep gilt. Hier ist ‚ mein eigenes Arbeitsbeispiel: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.

Antwort

Ich spreche nicht fließend sed, aber es ist einfach, dies in awk zu tun:

awk "/bar/{getline;next} 1" foo.txt 

Die Das awk-Skript lautet: Für eine Zeile mit einem Balken rufen Sie die nächste Zeile (getline) ab und überspringen dann alle nachfolgenden Verarbeitungen (next). Das 1-Muster am Ende druckt die verbleibenden Zeilen.

Update

Wie im Kommentar ausgeführt, funktionierte die obige Lösung nicht mit aufeinanderfolgenden bar. Hier ist eine überarbeitete Lösung, die dies berücksichtigt:

awk "/bar/ {while (/bar/ && getline>0) ; next} 1" foo.txt 

Wir lesen jetzt weiter, um alle / bar / Zeilen zu überspringen.

Kommentare

  • Um grep -A 100% zu replizieren, müssen Sie auch eine beliebige Anzahl aufeinanderfolgender Zeilen korrekt (durch Entfernen des gesamten Blocks und 1 Zeile danach).

Antwort

Sie sollten die Skriptfunktionen von sed nutzen, um dies zu erreichen.

$ sed -e "/bar/ { $!N d }" sample1.txt 

Beispieldaten:

$ cat sample1.txt foo bar biz baz buz 

Mit dem Befehl „N“ wird die nächste Eingabezeile an den Musterbereich angehängt. In Kombination mit der Zeile aus der Musterübereinstimmung (/ bar /) werden die Zeilen gelöscht, die Sie löschen möchten. Sie können dies dann tun normal löschen mit dem Befehl „d“.

Kommentare

  • Wie gebe ich eine neue Zeile in die Konsole ein? Oder ist dies nur ein Skript?
  • @ jakub.g: mit GNU sed: sed -e '/bar/{N;d}' sample1.txt

Antwort

Wenn eine Zeile unmittelbar nach einer Übereinstimmung entfernt werden soll, muss Ihr sed -Programm aufeinanderfolgende Übereinstimmungen berücksichtigen. Mit anderen Worten, wenn Sie eine Zeile nach einer Übereinstimmung entfernen, die auch übereinstimmt, sollten Sie wahrscheinlich auch die Zeile entfernen, die darauf folgt.

Sie ist einfach genug implementiert – aber Sie müssen ein wenig zurückblicken

printf %s\\n 0 match 2 match match \ 5 6 match match match \ 10 11 12 match 14 15 | sed -ne"x;/match/!{g;//!p;}" 

 0 6 11 12 15  

Dabei werden die Halte- und Musterbereiche für jede eingelesene Zeile vertauscht, sodass die letzte Zeile jedes Mal mit der aktuellen Zeile verglichen werden kann. Wenn also sed eine Zeile liest, tauscht sie den Inhalt ihrer Puffer aus – und die vorherige Zeile ist dann der Inhalt ihres Bearbeitungspuffers, während die aktuelle Zeile in den Haltebereich gestellt wird.

Also sed überprüft die vorherige Zeile auf Übereinstimmung mit match und wenn Die ! hat die beiden Ausdrücke in der { -Funktion } nicht ausgeführt. sed

et den Haltebereich durch Überschreiben des Musterbereichs – was bedeutet, dass sich die aktuelle Zeile dann sowohl im Halte- als auch im Musterbereich befindet – und dann überprüft es//, ob es mit seinem zuletzt kompilierten regulären Ausdruck übereinstimmt – match – und Wenn es nicht match ist, wirdpgedruckt.

Dies bedeutet, dass eine Zeile nur gedruckt wird, wenn sie nicht match und die unmittelbar vorhergehende Zeile nicht ist match . Außerdem wird auf unnötige Auslagerungen für Sequenzen von match es verzichtet.

Wenn Sie eine Version wünschen, die eine beliebige Anzahl von Zeilen löschen kann Wenn ein match auftritt, ist etwas mehr Arbeit erforderlich:

printf %s\\n 1 2 3 4 match \ match match 8 \ 9 10 11 12 13 \ 14 match match \ 17 18 19 20 21 | sed -net -e"/match/{h;n;//h;//!H;G;s/\n/&/5;D;}" -ep 

. ..ersetzen Sie die 5 durch die Anzahl der Zeilen (einschließlich der übereinstimmenden Zeile) , die Sie entfernen möchten …


1 2 3 4 12 13 14 21 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.