Niech sed ignoruje niepasujące wiersze


94

Jak mogę ustawić sedfiltrowanie pasujących wierszy według jakiegoś wyrażenia, ale ignorować niedopasowane wiersze, zamiast pozwolić im drukować?

Jako prawdziwy przykład chcę uruchomić scalac(kompilator Scala) na zestawie plików i odczytać z jego -verbosedanych wyjściowych .classutworzone pliki. scalac -verbosewyświetla kilka komunikatów, ale interesują nas tylko te z formularza [wrote some-class-name.class]. To, co obecnie robię, to ( |&jest to sposób basha 4.0 na przesłanie stderr do następnego programu):

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

Spowoduje to wyodrębnienie nazw plików z wiadomości, które nas interesują, ale także przepuści wszystkie inne wiadomości bez zmian! Oczywiście moglibyśmy zamiast tego zrobić:

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

co działa, ale wygląda bardzo podobnie do obejścia prawdziwego problemu, czyli instrukcji sedignorowania niepasujących wierszy z danych wejściowych. Jak więc to robimy?


2
Zaakceptowaną odpowiedzią powinna być ta przesłana przez mouviciel: stackoverflow.com/a/1665574/869951
Oliver

Odpowiedzi:


90

Inny sposób z prostym sedem:

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

s///jest podstawieniem, tbez etykiety warunkowo pomija wszystkie kolejne polecenia, dusuwa linię.

Nie ma potrzeby używania perl ani grep.

(zredagowane za sugestią Nicholasa Rileya)


3
W systemie OS X 10.8.2 musiałem oddzielić txi dużyć nowej linii zamiast średnika, jak otrzymywałem undefined label 'x;d;:x'.
davidchambers

6
Jeszcze lepiej: sed -e 's/.../.../' -e 'tx' -e 'd' -e ':x'(sugerowane w komentarzu do podobnego pytania ).
davidchambers

1
„t” będzie przenieść na końcu skryptu jeśli nie etykieta jest dostarczany, więc prościej: sed -e 's/.../.../' -e 't' -e 'd'.
Nicholas Riley

Ludzie nie znają znaczenia -eopcji, więc nie wspominaj o niej ogólnie.
Fredrick Gauss

246

Jeśli nie chcesz drukować niezgodnych wierszy, możesz użyć kombinacji

  • -n opcja, która mówi sedowi, żeby nie drukował
  • p flaga, która każe sedowi wypisać to, co zostało dopasowane

To daje:

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

3
Wadą tego podejścia jest to, że jeśli masz wiele pasujących wyrażeń, wynik zostanie również wydrukowany wiele razy. Na przykład: echo foo | sed -n -e 's/foo/bar/p' -e 's/bar/oof/p'wyświetli oba bariw oofoddzielnych wierszach. Chociaż odmiana goto-label również nie obsługuje wielu wzorców, ponieważ usunie linię, jeśli pierwszy wzorzec nie pasuje.
Rapsey,

@Rapsey to dlatego, że każesz mu wydrukować dwa razy. W pojedynczym poleceniu seda, które nakazałeś mu wydrukować dwukrotnie, każda instancja jest drukowana in-situ (lub może buforowana). Musiałbyś albo użyć potoku zamiast -e, albo wstawić 'p' tylko na ostatnie -e.
mikrobiologiczny

@Rapsey: zobacz moją odpowiedź na ten temat
Amessihel

@microbial, nie zadziała, ponieważ ostatnia flaga p będzie działać na każdym dopasowanym wierszu przez ostatnie wyrażenie podstawienia.
Amessihel


0

Rapsey poruszył istotną kwestię dotyczącą wyrażeń wielokrotnych podstawień.

  • Po pierwsze, cytując odpowiedź Unix SE , możesz „poprzedzić większość poleceń seda adresem, aby ograniczyć linie, do których się one odnoszą”.
  • Po drugie, możesz pogrupować polecenia w nawiasach klamrowych {}(oddzielone średnikiem ;lub nową linią)
  • Po trzecie, dodaj flagę print p do ostatniego podstawienia

Składnia:

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

Przykład (zobacz dokument tutaj, aby uzyskać więcej informacji):

  • Kod:

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

    kaka
    

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.