Demander à sed d'ignorer les lignes non correspondantes


91

Comment puis-je faire sed des lignes de filtrage correspondant à une expression, mais ignorer les lignes non correspondantes, au lieu de les laisser s'imprimer?

À titre d'exemple réel, je veux exécuter scalac(le compilateur Scala) sur un ensemble de fichiers et lire à partir de sa -verbosesortie les .classfichiers créés. scalac -verboserenvoie un tas de messages, mais nous ne sommes intéressés que par ceux du formulaire [wrote some-class-name.class]. Ce que je fais actuellement est la suivante ( |&est la manière de bash 4.0 de diriger stderr vers le programme suivant):

$ scalac -verbose some-file.scala ... |& sed 's/^\[wrote \(.*\.class\)\]$/\1/'

Cela extraira les noms de fichiers des messages qui nous intéressent, mais laissera également passer tous les autres messages inchangés! Bien sûr, nous pourrions faire à la place ceci:

$ scalac -verbose some-file.scala ... |& grep '^\[wrote .*\.class\]$' |
  sed 's/^\[wrote \(.*\.class\)\]$/\1/'

qui fonctionne mais ressemble beaucoup à contourner le vrai problème, qui est de savoir comment demander sedà ignorer les lignes non correspondantes de l'entrée. Alors, comment faisons-nous cela?


2
La réponse acceptée devrait être celle de mouviciel: stackoverflow.com/a/1665574/869951
Oliver

Réponses:


89

Une autre façon avec le sed plain:

sed -e 's/.../.../;t;d'

s///est une substitution, tsans aucune étiquette saute conditionnellement toutes les commandes suivantes,d supprime la ligne.

Pas besoin de perl ou de grep.

(édité après la suggestion de Nicholas Riley)


3
Sous OS X 10.8.2, je devais séparer txet davec une nouvelle ligne plutôt qu'un point-virgule comme j'obtenais undefined label 'x;d;:x'.
davidchambers

6
Mieux encore: sed -e 's/.../.../' -e 'tx' -e 'd' -e ':x'(suggéré dans un commentaire sur une question similaire ).
davidchambers

1
« t » transférera à la fin du script si aucune étiquette est fourni, de manière plus simple: sed -e 's/.../.../' -e 't' -e 'd'.
Nicholas Riley

Les gens ne connaissent pas la signification de l' -eoption, alors ne le mentionnez pas en général.
Fredrick Gauss

242

Si vous ne souhaitez pas imprimer des lignes qui ne correspondent pas, vous pouvez utiliser la combinaison de

  • -n option qui dit à sed de ne pas imprimer
  • p indicateur qui indique à sed d'afficher ce qui correspond

Cela donne:

sed -n 's/.../.../p'

3
Un inconvénient de cette approche est que si vous avez plusieurs expressions qui correspondent, le résultat sera également imprimé plusieurs fois. Par exemple: echo foo | sed -n -e 's/foo/bar/p' -e 's/bar/oof/p'affichera les deux baret oofsur des lignes séparées. Bien que la variété goto-label ne puisse pas non plus gérer plusieurs modèles puisqu'elle supprimera la ligne si le premier modèle ne correspond pas.
Rapsey

@Rapsey c'est parce que vous lui dites d'imprimer deux fois. Dans la commande sed unique, vous lui avez dit d'imprimer deux fois, chaque instance est imprimée in situ (ou peut-être tamponnée). Vous auriez soit à pipe au lieu de -e, soit à ne mettre «p» que sur le dernier -e.
microbien

@Rapsey: voir ma réponse sur ce point pertinent
Amessihel

@microbial, cela ne fonctionnera pas car le dernier indicateur p fonctionnera sur chaque ligne correspondante par la dernière expression de substitution.
Amessihel le

1

Utilisez Perl:

... |& perl -ne 'print "$1\n" if /^\[wrote (.*\.class)\]$/'


0

Rapsey a soulevé un point pertinent concernant les expressions de substitutions multiples.

  • Tout d'abord, citer une réponse Unix SE , vous pouvez "préfixer la plupart des commandes sed avec une adresse pour limiter les lignes auxquelles elles s'appliquent".
  • Deuxièmement, vous pouvez regrouper les commandes entre accolades {}(séparées par un point-virgule ;ou une nouvelle ligne)
  • Troisièmement, ajoutez le drapeau d'impression p sur la dernière substitution

Syntaxe:

sed -n -e '/^given_regexp/ {s/regexp1/replacement1/flags1;[...];s/regexp1/replacement1/flagsnp}'

Exemple (voir le document Here pour plus de détails):

  • Code:

    sed -n -e '/^ha/ {s/h/k/gp;s/a/e/g}' <<SAMPLE
    haha
    hihi
    SAMPLE
    
  • Résultat:

    kaka
    
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.