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.

79
demandé sur mklement0 2010-12-09 13:05:45

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
139
répondu dogbane 2010-12-09 12:56:14

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éfinit awk 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, le print avant nextgarantit 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 que 1 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.
5
répondu mklement0 2015-05-20 17:57:07

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

2
répondu glenn jackman 2010-12-09 15:17:15

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
répondu potong 2012-01-20 12:20:16