web-dev-qa-db-fra.com

sed ou awk: supprime n lignes suivant un motif

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.

86
Martin DeMello

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
148
dogbane

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 $countaprè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 cours
  • 1 est un raccourci couramment utilisé pour { print }; c'est-à-dire que la ligne en cours est simplement imprimée
    • Seules les lignes qui ne correspondent pas et qui ne sont pas sautées atteignent cette commande.
    • La raison pour laquelle 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.
5
mklement0

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

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

2
glenn jackman

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

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.

0
thakis