sed oder awk: Lösche n Zeilen nach einem Muster

105

Wie würde ich Muster und numerische Bereiche in sed mischen (oder einem ähnlichen Werkzeug - zum Beispiel awk)? Ich möchte bestimmte Zeilen in einer Datei abgleichen und die nächsten n Zeilen löschen, bevor ich fortfahre. Dies möchte ich als Teil einer Pipeline tun.

Martin DeMello
quelle

Antworten:

185

Ich werde es versuchen.

So löschen Sie 5 Zeilen nach einem Muster (einschließlich der Zeile mit dem Muster):

sed -e '/pattern/,+5d' file.txt

So löschen Sie 5 Zeilen nach einem Muster (ohne die Zeile mit dem Muster):

sed -e '/pattern/{n;N;N;N;N;d}' file.txt
Dogbane
quelle
14
Beachten Sie, dass das +NMuster eine GNU-Erweiterung ist. Ändern Sie die erste nin eine Nin Ihrem zweiten Beispiel, damit sie die Linie mit dem Muster enthält.
Bis auf weiteres angehalten.
2
Wie lösche ich alle Zeilen, nachdem das Muster abgeglichen wurde? Ich verwende sed -e '/ <! - # content end -> </ div> /, $ d' out.txt, aber es gibt einen Fehler, der besagt: sed: -e Ausdruck # 1, char 24: zusätzliche Zeichen danach Befehl Danke im Voraus.
N mol
8
Was passiert, ist ähnlich, aber in jedem Fall etwas anders. Definiert im ersten Rezept /pattern/,+5einen Bereich, der mit einer Zeile mit "pattern" ( /pattern/) beginnt und 5 Zeilen später endet ( +5). Das letzte Zeichen dist ein Befehl, der in jeder Zeile in diesem Bereich ausgeführt wird. Dies ist "Löschen". Im zweiten Rezept stimmt es nicht mit einem Bereich überein, sondern nur mit der Zeile, die das Muster enthält ( /pattern/), und führt dann eine Reihe von Befehlen aus : {n;N;N;N;N;d}, die im Grunde die nächste Zeile ( n) drucken und dann die nächsten 4 Zeilen lesen und schließlich verwerfen ( N;N;N;N;d).
Pimlottc
18
Auf Mac / OS X-Systemen müssen Sie vor der schließenden Klammer ein Semikolon sed -e '/pattern/{n;N;N;N;N;d;}' file.txt
einfügen
1
Der Vollständigkeit halber : Um alle Zeilen nach einem bestimmten Muster zu löschen, gehen Sie wie folgt vorsomething : sed -E '/^something$/,$d'Wo -Ebefindet sich der erweiterte reguläre Ausdruck für die POSIX-Portabilität?
not2qubit
7

Ohne GNU-Erweiterungen (zB unter macOS):

So löschen Sie 5 Zeilen nach einem Muster (einschließlich der Zeile mit dem Muster)

 sed -e '/pattern/{N;N;N;N;d;}'

In -i ''zu bearbeiten in-place.

Thakis
quelle
6

Einfache awkLösungen:

Angenommen, der reguläre Ausdruck, der zum Suchen übereinstimmender Zeilen verwendet werden soll, wird in der Shell-Variablen gespeichert $regexund die Anzahl der zu überspringenden Zeilen $count.

Wenn die übereinstimmende Zeile ebenfalls übersprungen werden soll ( $count + 1Zeilen werden übersprungen):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'

Wenn die passende Linie nicht sollte übersprungen werden soll ( $countZeilen nach der Übereinstimmung werden übersprungen):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; print; next } --skip >= 0 { next } 1'

Erläuterung:

  • -v regex="$regex" -v count="$count"definiert awkVariablen basierend auf gleichnamigen Shell- Variablen.
  • $0 ~ regex entspricht der interessierenden Linie
    • { skip=count; next }Initialisiert die Anzahl der Übersprungen und fährt mit der nächsten Zeile fort, wodurch die übereinstimmende Zeile effektiv übersprungen wird. in der 2. Lösung dieprint Vorher nextsicher, dass es nicht übersprungen wird.
    • --skip >= 0 Verringert die Anzahl der Übersprungen und ergreift Maßnahmen, wenn sie (noch)> = 0 ist, was bedeutet, dass die vorliegende Zeile übersprungen werden sollte.
    • { next } Fahren Sie mit der nächsten Zeile fort und überspringen Sie die aktuelle Zeile
  • 1ist eine häufig verwendete Abkürzung für { print }; Das heißt, die aktuelle Zeile wird einfach gedruckt
    • Nur nicht übereinstimmende und nicht übersprungene Zeilen erreichen diesen Befehl.
    • Der Grund 1dafür { print }ist, dass er 1als boolesches Muster interpretiert wird, das per Definition immer als wahr ausgewertet wird, was bedeutet, dass die zugehörige Aktion (Block) bedingungslos ausgeführt wird. Da in diesem Fall keine Aktion zugeordnet ist, wird awkstandardmäßig die Zeile gedruckt .
mklement0
quelle
3

Dies könnte für Sie funktionieren:

cat <<! >pattern_number.txt
> 5 3
> 10 1
> 15 5
> !
sed 's|\(\S*\) \(\S*\)|/\1/,+\2{//!d}|' pattern_number.txt |
sed -f - <(seq 21)
1 
2
3
4
5
9
10
12
13
14
15
21
Potong
quelle
10
Wow, das ist kryptisch.
Pimlottc
3
Eine clevere (wenn auch GNU-Sed-spezifische) Lösung, aber nur wenige Menschen werden davon profitieren, es sei denn, Sie fügen eine Erklärung hinzu. pattern_number.txtist eine zweispaltige Datei, die das Muster enthält, das in der ersten Spalte übereinstimmt, und in der zweiten die Anzahl der zu überspringenden Zeilen. Der erste sedBefehl wandelt die Datei in ein sedSkript um, das den entsprechenden Abgleich und das Überspringen ausführt. Dieses Skript wird über -fund stdin ( -) für den 2. sedBefehl bereitgestellt . Der 2. sedBefehl verarbeitet eine Beispiel-Ad-hoc-Eingabedatei, die aus der Ausgabe von erstellt wurde seq 21, um zu demonstrieren, dass sie funktioniert.
mklement0
Auch kommt die Lösung mit einer Einschränkung: Das Verfahren nutzt nicht die erste Zeile (die die Musterabgleich) zu überspringen , hat den Nebeneffekt , auch nicht das Überspringen doppelter Linien im Bereich.
mklement0
Das ist eine beeindruckende Verwendung von sed.
Travis Rodman
3

Verwenden von Perl

$ cat delete_5lines.txt
1
2
3
4
5 hello
6
7
8
9
10
11 hai
$ perl -ne ' BEGIN{$y=1} $y=$.  if /hello/ ; print if $y==1 or $.-$y > 5 ' delete_5lines.txt
1
2
3
4
11 hai
$
stack0114106
quelle
2

Mit dieser Lösung können Sie "n" als Parameter übergeben und Ihre Muster aus einer Datei lesen:

awk -v n=5 '
    NR == FNR {pattern[$0]; next}
    {
        for (patt in pattern) {
            if ($0 ~ patt) {
                print # remove if you want to exclude a matched line
                for (i=0; i<n; i++) getline
                next
            }
        }
        print
    }
' file.with.patterns -

Die Datei mit dem Namen "-" bedeutet stdin für awk, daher ist dies für Ihre Pipeline geeignet

Glenn Jackman
quelle
2
awk kann viel perlartiger sein als ich dachte!
Martin DeMello