sed ou awk: supprimer n Lignes suivant un motif
Comment mélanger des motifs et des plages numériques dans sed (ou tout autre outil similaire - awk par exemple)? Ce que je veux faire est de faire correspondre certaines lignes dans un fichier, et supprimer les N lignes suivantes Avant de continuer, et je veux le faire dans le cadre d'un pipeline.
4 réponses
Je vais essayer.
Pour supprimer 5 lignes après un motif (y compris la ligne avec le motif):
sed -e '/pattern/,+5d' file.txt
Pour supprimer 5 lignes après un motif (à l'exclusion de la ligne avec le motif):
sed -e '/pattern/{n;N;N;N;N;d}' file.txt
Solutions simples awk
:
Supposons que l'expression régulière à utiliser pour trouver les lignes correspondantes est stockée dans la variable shell $regex
, et le nombre de lignes à ignorer dans $count
.
Si le correspondant ligne aussi être ignorée ($count + 1
les lignes sont ignorées):
... | awk -v regex="$regex" -v count="$count" \
'$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'
Si le correspondant ligne pas être ignorée ($count
les lignes après le match sont sautée):
... | awk -v regex="$regex" -v count="$count" \
'$0 ~ regex { skip=count; print; next } --skip >= 0 { next } 1'
Explication:
-
-v regex="$regex" -v count="$count"
définitawk
variables basée sur shell des variables de même nom. -
$0 ~ regex
correspond à la ligne d'intérêt-
{ skip=count; next }
initialise le nombre de sauts et passe à la ligne suivante, en sautant efficacement la ligne correspondante; dans la 2ème solution, leprint
avantnext
garantit qu'il est pas ignoré. -
--skip >= 0
décrémente le nombre de sauts et prend des mesures s'il l'est (toujours) > = 0, ce qui implique que la ligne à portée de main doit être ignorée. -
{ next }
passe à la ligne suivante, sautant efficacement la ligne actuelle
-
-
1
est un raccourci couramment utilisé pour{ print }
; c'est-à-dire que la ligne actuelle est simplement imprimée- seules les lignes non correspondantes et non sautées atteignent cette commande.
- la raison pour laquelle
1
est équivalent à{ print }
est que1
est interprété comme un modèle booléen qui, par définition, évalue toujours à true, ce qui signifie que son action associée (bloc) est exécutée sans condition. Depuis, il est non " action associés dans ce cas,awk
par défaut impression la ligne.
Cette solution vous permet de passer "n" en paramètre et il lira vos motifs à partir d'un fichier:
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 -
Le fichier nommé " - " signifie stdin pour awk, donc cela convient à votre pipeline
Cela pourrait fonctionner pour vous:
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