Як вибрати перше виникнення між двома шаблонами, включаючи їх


27

Як я можу вибрати перше виникнення між двома шаблонами, включаючи їх. Переважно з використанням sedабо awk.

Я маю:

text
something P1 something
content1
content2
something P2 something
text
something P1 something
content3
content4
something P2 something
text

Я хочу, щоб перше виникнення рядків між P1 та P2 (включаючи рядок P1 та P2):

something P1 something
content1
content2
something P2 something

Відповіді:


22
sed '/P1/,/P2/!d;/P2/q'

... зробив би цю роботу портативно, dвибравши всі рядки, які !не потрапляють у діапазон, а потім, qвикористовуючи перший раз, коли він стикається в кінці діапазону. Він не відмовляється від P2, що передує P1, і він не вимагає простого запису синтаксису GNU.


Відмінно! Набагато краще, ніж у мене.
муру

1
@muru - Часто простіше уникнути викривлень, якщо ви намагаєтеся націлити автовідбиток - нехай цикл працює для вас. Така звичка я все-таки потрапив. Я думаю, що це, мабуть, найкраще описується як чорнослив проти вибраного методу - я, як правило, перетворюю на заперечення шаблону, а не на пошук.
mikeserv

Це буде зависло при обробці величезного розміру файлу.
Мозок90

@ Brain90 - не слід. якщо ви можете надійно відтворити скаргу, вам слід звернутися до технічного обслуговування вашої sed... thats bug у вашому sedзапущеному, а не в tbe-скрипті вище.
mikeserv

1
@mikeserv Я б не сказав цього, якби не був. Ваше занепокоєння з приводу того, чи мені байдуже пара персонажів, дивне: я помітив, що вираз sed працює як з /P2/qмоєю системою, так і без неї ; Це воно. Мені щось цікаво і хотілося поділитися тим, що я знайшов.
Олексій Магура

8

з awk

awk '/P1/{a=1};a;/P2/{exit}' file
something P1 something
content1
content2
something P2 something

8

В sed:

sed -n '/P1/,/P2/p; /P2/q'
  • -nпридушує друк за замовчуванням, і ви друкуєте рядки між відповідними діапазонами адрес за допомогою pкоманди.
  • Зазвичай це відповідало б обом розділам, тому ви закриваєте ( q), коли перші P2збіги.

Це не вдасться, якщо P2вийде раніше P1. Щоб вирішити цей випадок, спробуйте:

sed -n '/P1/,/P2/{p; /P2/q}'

1
Я не погоджуюсь; Відповідь mikeserv не краща за вашу.
G-Man каже "Відновити Моніку"

@ g-man - пшау. але я думав саме те саме.
mikeserv

1
@gman - ніпе. тепер я розумію. міни краще. ні {стек}!
mikeserv

1

Якщо ви хочете пропустити самі шаблони, ось awkверсія:

awk '/P2/ {exit} /P1/ {f=1; next} f' file

Працює для мене. Чи можете ви додати трохи більше інформації про те, як працює команда?
0xAffe

1

Більш просте awkрішення (роду- на півдорозі між відповіддю Iruvar в і  відповіді Мура в , але не використовує змінний):

awk '/P1/,/P2/ { print }  /P2/ { exit }'

і, як зауважив Муру, якщо перший P2 з'явиться перед першим P1, це нічого не надрукує.

Звичайно, якщо ви хочете надрукувати всі діапазони P1-P2:

something P1 something
content1
content2
something P2 something
something P1 something
content3
content4
something P2 something

просто залиште exitчастину:

awk '/P1/,/P2/ { print }'

1
awk '/P1/,/P2/{print;f=1} f&&/P2/{exit}' data

Вийдіть негайно після друку, не раніше.


0

Щоб пропустити самі шаблони та показати лише перший блок узгодження в одному sed GNU:

sed -nre '/STARTPATTERN/ {:a;n;/ENDPATTERN/{b;};p;ba}' file
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.