wake-up-neo.net

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

Wie mische ich Muster und numerische Bereiche in sed (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 Sie fortfahren, und ich möchte dies als Teil einer Pipeline tun.

86
Martin DeMello

Ich werde es versuchen.

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

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

5 Zeilen nach einem Muster löschen (ohne die Linie mit dem Muster):

sed -e '/pattern/{n;N;N;N;N;d}' file.txt
148
dogbane

Einfache awk-Lösungen:

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

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

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

Wenn die übereinstimmende Zeile nicht übersprungen werden soll ($count Zeilen nach wird die Übereinstimmung übersprungen):

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

Erklärung:

  • -v regex="$regex" -v count="$count" definiert awk-Variablen basierend auf Shell -Variablen desselben Namens.
  • $0 ~ regex entspricht der interessierenden Zeile
    • { skip=count; next } initialisiert den Übersprungzähler und geht zur nächsten Zeile über, wobei die übereinstimmende Zeile effektiv übersprungen wird; In der zweiten Lösung stellt die Variable print vor next sicher, dass nicht übersprungen wird.
    • --skip >= 0 dekrementiert die Anzahl der Übersprünge und ergreift Maßnahmen, wenn (noch)> = 0 ist, was bedeutet, dass die betreffende Zeile übersprungen werden soll.
    • { next } geht zur nächsten Zeile über und überspringt die aktuelle Zeile effektiv
  • 1 ist 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, aus dem 1 äquivalent zu { print } ist, besteht darin, dass 1 als boolesches Muster interpretiert wird, das per Definition immer als "true" ausgewertet wird. Dies bedeutet, dass die zugehörige Aktion (Block) unbedingt ausgeführt wird. Da in diesem Fall eine no - Aktion vorliegt, wird awk standardmäßig auf printing der Zeile gesetzt.
5
mklement0

Das 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
2
potong

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" und ist daher für Ihre Pipeline geeignet

2
glenn jackman

Perl verwenden

$ 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
$
0
stack0114106

Ohne GNU -Erweiterungen (z. B. unter macOS):

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

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

Fügen Sie -i '' hinzu, um ihn direkt zu bearbeiten.

0
thakis