Как выбрать первое вхождение между двумя образцами, включая их


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

Это будет зависать при обработке огромного fileSize.
Brain90

@ Brain90 - не должен. если вы можете надежно воспроизвести вашу жалобу, вам следует обратиться к сопровождающему вашего sed... это ошибка в 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 - pshaw. но я просто думал о том же.
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

Чтобы пропустить сами шаблоны и показать только первый соответствующий блок в одном GNU sed:

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