web-dev-qa-db-fra.com

Supprimer la ligne contenant une certaine chaîne et la ligne suivante

J'utilise ceci

cat foo.txt | sed '/bar/d'

pour supprimer les lignes contenant la chaîne bar dans le fichier.

Je voudrais cependant supprimer ces lignes et la ligne juste après. De préférence dans sed, awk ou tout autre outil disponible dans MinGW32.

C'est une sorte d'inverse de ce que je peux obtenir dans grep avec -A et -B pour imprimer les lignes correspondantes ainsi que les lignes avant/après la ligne correspondante.

Existe-t-il un moyen facile de le réaliser?

77
jakub.g

Si vous avez GNU sed (donc Linux ou Cygwin non embarqué):

sed '/bar/,+1 d'

Si vous avez bar sur deux lignes consécutives, cela supprimera la deuxième ligne sans l'analyser. Par exemple, si vous avez un fichier à 3 lignes bar/bar/foo, la ligne foo restera.

Si bar peut se produire sur des lignes consécutives, vous pouvez faire:

awk '/bar/{n=2}; n {n--; next}; 1' < infile > outfile

qui peut être adapté pour supprimer plus de 2 lignes en changeant les 2 ci-dessus avec le nombre de lignes à supprimer, y compris celle correspondante.

Sinon, c'est facile à faire dans sed avec @ solution MichaelRollins ou:

sed '/bar/,/^/d' < infile > outfile
17
Stéphane Chazelas

Je ne parle pas couramment sed, mais il est facile de le faire en awk:

awk '/bar/{getline;next} 1' foo.txt 

Le script awk indique: pour une ligne contenant une barre, obtenez la ligne suivante (getline), puis ignorez tous les traitements ultérieurs (suivant). Le motif 1 à la fin imprime les lignes restantes.

Mise à jour

Comme indiqué dans le commentaire, la solution ci-dessus ne fonctionnait pas avec des bar consécutifs. Voici une solution révisée, qui la prend en considération:

awk '/bar/ {while (/bar/ && getline>0) ; next} 1' foo.txt 

Nous continuons maintenant à lire pour ignorer toutes les lignes/bar /.

12
Hai Vu

Vous souhaiterez utiliser les capacités de script de sed pour y parvenir.

$ sed -e '/bar/ { 
 $!N
 d
 }' sample1.txt

Exemples de données:

$ cat sample1.txt 
foo
bar
biz
baz
buz

La commande "N" ajoute la ligne d'entrée suivante dans l'espace de motif. Ceci combiné avec la ligne de la correspondance de motif (/ bar /) sera les lignes que vous souhaitez supprimer. Vous pouvez ensuite supprimer normalement avec la commande "d".

7
Michael Rollins

Si une ligne immédiatement après une correspondance doit être supprimée, votre programme sed devra considérer des correspondances consécutives. En d'autres termes, si vous supprimez une ligne après une correspondance qui correspond également, vous devriez probablement supprimer également la ligne qui suit.

Il est implémenté simplement - mais il faut regarder un peu en arrière.

printf %s\\n     0 match 2 match match \
                 5 6 match match match \
                 10 11 12 match 14 15  |
sed -ne'x;/match/!{g;//!p;}'

0
6
11
12
15

Il fonctionne en échangeant les espaces d'attente et de motif pour chaque ligne lue - de sorte que la dernière ligne peut être comparée à la fois à chaque fois. Ainsi, lorsque sed lit une ligne, il échange le contenu de ses tampons - et la ligne précédente est alors le contenu de son tampon d'édition, tandis que la ligne actuelle est mise en attente.

Donc sed vérifie la ligne précédente pour une correspondance avec match, et si son ! pas trouvé les deux expressions dans le { une fonction } sont exécutés. sed va get l'espace de rétention en écrasant l'espace de motif - ce qui signifie que la ligne actuelle se trouve alors à la fois dans les espaces de maintien et de motif - puis il // recherchez une correspondance avec sa dernière expression régulière compilée - match - et si it ne le fait pas match c'est pimprimé.

Cela signifie qu'une ligne n'est imprimée que si elle ne --- matchet la ligne immédiatement précédente ne --- match =. Il renonce également à tout échange inutile pour des séquences de match es.

Si vous vouliez une version qui pourrait supprimer un nombre arbitraire de lignes se produisant après un match, il faudrait un peu plus de travail:

printf %s\\n    1 2 3 4 match  \
                match match 8  \
                9 10 11 12 13  \
                14 match match \
                17 18 19 20 21 |
sed -net -e'/match/{h;n;//h;//!H;G;s/\n/&/5;D;}' -ep

... remplacez le 5 par le nombre de lignes (y compris la ligne correspondante) que vous souhaitez supprimer ...


1
2
3
4
12
13
14
21
2
mikeserv