Supprimer la ligne contenant certaines chaînes et la ligne suivante

71

Je l'utilise

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

supprimer les lignes contenant la chaîne bardans le fichier.

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

C'est une sorte d'inverse de ce que je peux obtenir grepavec -Aet -Bimprimer des lignes de correspondance ainsi que des lignes avant / après la ligne correspondante.

Y a-t-il un moyen facile d'y parvenir?

jakub.g
la source
2
Juste pour information: j'analyse des journaux dans lesquels les entrées sont à deux lignes. Je veux donc trouver une entrée correspondant au modèle et la supprimer ainsi que la ligne suivante. Par conséquent, je n'ai pas besoin de gérer des lignes de match consécutives, mais merci quand même pour l'intégralité de vos réponses!
jakub.g

Réponses:

75

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

sed '/bar/,+1 d'

Si vous avez bardeux lignes consécutives, cela effacera la deuxième ligne sans l’analyser. Par exemple, si vous avez un fichier 3 lignes bar/ bar/ foo, la fooligne restera.

Gilles, arrête de faire le mal
la source
1
+1 pour la longueur :) Dans mon exemple particulier, je n'ai pas de suite, bardonc celui-ci est très facile à mémoriser.
jakub.g
11
sed '/bar/d'si vous voulez juste "Supprimer la ligne contenant certaines chaînes" et pas la suivante.
AJP
Si je veux supprimer toutes les lignes après les maths, alors?
Pandya
1
@ Pandya C'est différent. Vous pouvez utiliser, par exemplesed '/math/q'
Gilles 'SO- arrête d'être méchant'
1
@AK Si vous voulez simplement supprimer la ligne correspondante, c'est encore plus simple:sed '/bar/d'
Gilles, alors arrête d'être méchant
16

Si barpeut 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 modifiant les 2 précédentes avec le nombre de lignes à supprimer, y compris celle correspondante.

Sinon, cela se fait facilement sedavec la solution de @MichaelRollins ou:

sed '/bar/,/^/d' < infile > outfile
Stéphane Chazelas
la source
L’autre atout de la solution AWK est que je peux remplacer /bar/par /bar|baz|whatever/. Dans sedcette syntaxe ne semble pas fonctionner.
mardi
@ jakub.g, j'ai GNU sed (v4.4 maintenant). Pas sûr des autres. Ce que je sais, c'est qu'il utilise par défaut la syntaxe des expressions rationnelles "de base", c'est pourquoi votre exemple n'a pas fonctionné. Pour obtenir ce que vous voulez, vous pouvez soit mettre une barre oblique inverse devant chaque ligne verticale, soit demander sedd’utiliser des expressions régulières "étendues". Plus d'informations ici: gnu.org/software/sed/manual/html_node/… . S'il vous plaît noter que cela est applicable à grepainsi. Voici mon exemple de travail: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.
Victor Yarema
12

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

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

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

Mise à jour

Comme indiqué dans le commentaire, la solution ci-dessus ne fonctionnait pas avec consécutif bar. Voici une solution révisée qui en tient compte:

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

Nous continuons maintenant à lire pour sauter tous les / bar / lignes.

Hai Vu
la source
1
Pour répliquer à grep -A100%, vous devez également gérer barcorrectement n'importe quel nombre de lignes consécutives (en supprimant le bloc entier et 1 ligne après).
jw013
7

Vous voudrez utiliser les capacités de script de sed pour accomplir cela.

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

Échantillon de données:

$ cat sample1.txt 
foo
bar
biz
baz
buz

La commande "N" ajoute la ligne suivante dans l’espace du modèle. Ceci combiné avec la ligne de la correspondance de modèle (/ bar /) sera les lignes que vous souhaitez supprimer. Vous pouvez ensuite supprimer normalement avec la commande "d".

Michael Rollins
la source
Comment taper une nouvelle ligne dans la console? Ou est-ce seulement un script?
jakub.g
@ jakub.g: avec GNU sed:sed -e '/bar/{N;d}' sample1.txt
Cyrus
2

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

Il est simplement mis en œuvre - mais vous devez 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

Cela fonctionne en échangeant des espaces de maintien et de motif pour chaque ligne lue - de sorte que la dernière ligne puisse être comparée au courant à chaque fois. Ainsi, lors de la sedlecture d'une ligne, il échange le contenu de ses tampons. La ligne précédente correspond alors au contenu de son tampon d'édition, tandis que la ligne actuelle est mise en attente.

Donc, sedvérifie la correspondance sur la ligne précédente match, et si elle !n’est pas trouvée, les deux expressions de la {fonction }sont exécutées. sedsera get l'espace de prise en réécrivant l'espace de travail - ce qui signifie que la ligne courante est alors dans les deux espaces de maintien et motif - et il le //vérifier pour un match à son expression régulière plus récemment compilé - match- et si elle ne fonctionne pas , matchil est pimprimé.

Cela signifie qu'une ligne n'est imprimée que si ce n'est pas le cas et la ligne immédiatement précédente ne l'est pas . Il supprime également tout échange inutile de séquences d' es.match matchmatch

Si vous voulez une version capable de supprimer un nombre arbitraire de lignes apparaissant après, matchil vous faudra 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 nombre 5 par le nombre de lignes (y compris la ligne correspondante) que vous souhaitez supprimer ...


1
2
3
4
12
13
14
21
Mikeserv
la source