2009-11-03 5 views
62

Comment faire pour sed filtrer des lignes correspondant à une expression, mais ignorer les lignes qui ne correspondent pas, au lieu de les laisser imprimer?Avoir sed ignorer les lignes non-correspondantes

Comme un exemple concret, je veux courir scalac (le compilateur Scala) sur un ensemble de fichiers, et lire à partir de sa sortie -verbose les fichiers créés .class. scalac -verbose sort un tas de messages, mais nous sommes seulement intéressés par ceux du formulaire [wrote some-class-name.class]. Ce que je suis en train de faire est ce (|& est le moyen de tuyau stderr bash 4.0 sur le prochain programme):

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

Cela va extraire les noms de fichiers des messages qui nous intéressent, mais laissez également tous les autres messages passer inchangé! 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 à faire le tour du problème réel, ce qui est de savoir comment instruire sed d'ignorer les lignes qui ne correspondent pas à partir de l'entrée. Alors, comment faisons-nous cela?

Répondre

65

Une autre façon avec plaine sed:

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

s/// est un substituion, t sans étiquette saute sous condition toutes les commandes suivantes, d ligne supprime.

Pas besoin de perl ou grep.

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

+3

Sous OS X 10.8.2, je devais séparer 'tx' et' d' avec une nouvelle ligne plutôt qu'avec un point-virgule car j'obtenais 'label non défini 'x; d;: x''. – davidchambers

+4

Encore mieux: 'sed -e 's /.../.../' -e 'tx' -e 'd' -e ': x'' (suggéré dans un commentaire sur une [question similaire] (http : //stackoverflow.com/a/1252191/312785)). – davidchambers

+1

't' sera transféré à la fin du script si aucune étiquette n'est fournie, donc plus simple: 'sed -e 's /.../.../' -e 't' -e 'd''. –

3

Utiliser Perl:

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

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

  • l'option -n qui indique à Sed pas imprimer
  • p drapeau qui indique à sed d'imprimer c'est adapté

Cela donne:

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

Cela devrait être la réponse acceptée –

+1

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 'bar' et' oof' sur des lignes séparées. Bien que la variété goto-label ne puisse pas gérer plusieurs motifs, elle supprimera la ligne si le premier motif ne correspond pas. – Rapsey

Questions connexes