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.
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
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 effektiv1
ist eine häufig verwendete Abkürzung für { print }
; Das heißt, die aktuelle Zeile wird einfach gedruckt 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.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
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
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
$
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.