Нехай sed ігнорує невідповідні рядки


93

Як я можу зробити sedрядки відповідності фільтру відповідно до якогось виразу, але ігнорувати невідповідні рядки, замість того, щоб дозволити їм друкуватись?

Як реальний приклад, я хочу запустити scalac(компілятор Scala) на наборі файлів і прочитати з його -verboseрезультатів .classстворені файли. scalac -verboseвидає купу повідомлень, але нас цікавлять лише ті форми [wrote some-class-name.class]. На даний момент я роблю це ( |&це спосіб bash 4.0 до конвеєра stderr до наступної програми):

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

Це витягне імена файлів із повідомлень, які нас цікавлять, але також дозволить всім іншим повідомленням проходити без змін! Звичайно, ми могли б зробити замість цього:

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

що працює, але схоже на те, щоб обійти справжню проблему, тобто вказівку sedігнорувати невідповідні рядки з вводу. То як ми це робимо?


2
Прийнятий відповідь повинен бути один на mouviciel: stackoverflow.com/a/1665574/869951
Олівер

Відповіді:


90

Інший спосіб із звичайним sed:

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

s///є заміною, tбез будь-якої мітки умовно пропускає всі наступні команди, dвидаляє рядок.

Немає потреби в perl або grep.

(відредаговано за пропозицією Ніколаса Райлі)


3
На OS X 10.8.2 мені довелося розділити txі dз новим рядком , а не крапкою з комою , як я отримував undefined label 'x;d;:x'.
davidchambers

6
Ще краще: sed -e 's/.../.../' -e 'tx' -e 'd' -e ':x'(запропоновано в коментарі до подібного питання ).
davidchambers

1
«Т» перерахує до кінця сценарію , якщо мітка не поставляється, так простіше: sed -e 's/.../.../' -e 't' -e 'd'.
Ніколас Райлі

Люди не знають значення -eваріанту, тому загалом не згадують про нього.
Фредрік Гаус,

246

Якщо ви не хочете друкувати рядки, які не збігаються, ви можете використовувати комбінацію

  • -n параметр, який говорить sed не друкувати
  • p прапор, який говорить sed надрукувати відповідне

Це дає:

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

3
Недоліком цього підходу є те, що якщо у вас є кілька збігів виразів, результат також буде надруковано кілька разів. Наприклад: echo foo | sed -n -e 's/foo/bar/p' -e 's/bar/oof/p'буде виводити як окремі рядки, так barі oofокремі. Хоча сорт goto-label не може обробляти кілька шаблонів, оскільки він буде видаляти рядок, якщо перший шаблон не відповідає.
Rapsey

@Rapsey це тому, що ви велите йому друкувати двічі. В одній команді sed ви сказали друкувати двічі, кожен екземпляр друкується in-situ (або, можливо, буферизується). Вам доведеться або вставити конвеєр замість -e, або лише поставити 'p' на останньому -e.
мікробна

@Rapsey: див. Мою відповідь з цього приводу
Амессіхель,

@microbial, це не буде працювати, оскільки останній прапор p буде працювати на кожному узгодженому рядку за останнім виразом заміни.
Amessihel


0

Репсі підняв відповідну тему щодо виразів множинного заміщення.

  • По-перше, цитуючи відповідь Unix SE , ви можете "додати до більшості команд sed префікс адресою, щоб обмежити рядки, до яких вони застосовуються".
  • По-друге, ви можете групувати команди в фігурних дужках {}(відокремлюючи їх крапкою з комою ;або новим рядком)
  • По-третє, додайте прапор друку p на останню заміну

Синтаксис:

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

Приклад (докладніше див. Тут документ ):

  • Код:

    sed -n -e '/^ha/ {s/h/k/gp;s/a/e/g}' <<SAMPLE
    haha
    hihi
    SAMPLE
    
  • Результат:

    kaka
    

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.