Comment pourrais-je mélanger des modèles et des plages numériques dans sed (ou tout autre outil similaire - awk par exemple)? Ce que je veux faire, c'est faire correspondre certaines lignes d'un fichier et supprimer les n lignes suivantes avant de poursuivre, et je souhaite le faire dans le cadre d'un pipeline.
Je vais essayer ça.
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
Simple awk
solutions:
Supposons que l'expression régulière à utiliser pour rechercher les lignes correspondantes soit stockée dans la variable Shell $regex
, ainsi que le nombre de lignes à ignorer dans $count
.
Si la la ligne correspondante doit aussi être ignorée} _ (les lignes $count + 1
sont ignorées):
... | awk -v regex="$regex" -v count="$count" \
'$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'
Si le la ligne correspondante doit être ignorée pas (les lignes $count
après sont ignorées):
... | 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éfinit les variables awk
basées sur les variables Shell du 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 effectivement la ligne correspondante; Dans la 2ème solution, le print
avant next
garantit qu'il est pas ignoré.--skip >= 0
décrémente le nombre de sauts et prend des mesures s'il est (toujours)> = 0, ce qui implique que la ligne en main doit être ignorée.{ next }
passe à la ligne suivante, sautant effectivement la ligne en cours1
est un raccourci couramment utilisé pour { print }
; c'est-à-dire que la ligne en cours est simplement imprimée 1
est équivalent à { print }
est que 1
est interprété comme un modèle booléen qui, par définition, a toujours la valeur true, ce qui signifie que l'action associée (le bloc) est exécutée sans condition. Comme il y a une action associée à no dans ce cas, awk
est défini par défaut sur printing la ligne.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
Cette solution vous permet de passer "n" en paramètre et lira vos patterns à 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, il convient donc à votre pipeline
Utiliser 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
$
Sans extensions GNU (par exemple sur macOS):
Pour supprimer 5 lignes après un motif (y compris la ligne avec le motif)
sed -e '/pattern/{N;N;N;N;d;}'
Ajoutez -i ''
pour éditer sur place.