Intereting Posts
Как отлаживать случайные перезагрузки, без паники ядра встроенной системы? Как два идентичных виртуальных адреса указывают на разные физические адреса? renice не работает в macOS Sierra Вопрос синхронизации Rsync NFS Неожиданное поведение совпадения в sshd_config Есть ли какая-либо программа для обеспечения согласованного интерфейса для нескольких типов архивов? Создание имен пользователей с проверкой дублирования и их добавление в LDAP Solus OS сломанная загрузка Обрезка дерева пакетов с помощью apt-get и yum Как создать CronJob для запуска команд при перезагрузке? Удаление числовых значений в определенных столбцах при сохранении минус-знаков? Есть ли способ понять, почему требуется определенная зависимость пакета? Как использовать MEncoder для кодирования всех png-файлов (в текущем каталоге) в качестве файла avi в порядке изменения даты? Заменить текст значениями ЛУКС-кодовая фраза не работает

захватить текст по шаблону с началом и конечным тегом в нескольких строках

Я хочу захватить несколько строк в файле с шаблоном, у которого есть начальный и конечный теги неровным способом.

Например, у меня есть следующий ввод:

file.txt

START test1 test2 foo END some more text START test3 bar test4 test5 END even more START baz test6 END 

Теперь я хочу найти бар и распечатать все между START и END , так что я получу:

 START test3 bar test4 test5 END 

До сих пор я имею в виду следующую команду grep:

 grep -Pzo '(?s)START.*?bar.*?END' file.txt 

Проблема в том, что это выражение жадно и печатает:

 START # starts at first "START"-tag, not the next one test1 # test2 # foo # END # some # more text # START test3 bar test4 test5 END 

Это не делается с помощью grep flags -before-context / -after-context , потому что количество строк до и после может отличаться.

Инструмент, используемый при обработке текста, не имеет значения. Он должен работать над общей системой RedHat. Кроме того, чем быстрее инструмент захватывает линии, тем лучше будет. Потому что у меня есть лог-файлы объемом около 150 МБ.

Может ли кто-нибудь сказать мне, как достичь моей цели наилучшим образом?


Обновить:

Хорошо, я понял. Мне просто нужно было подумать о том, как построить мою команду из don_crissti . Вот решение:

 ed -s file.txt <<< $'g/bar/?START?,/END/p\nq\n' 

Большое вам спасибо за вашу очень быструю помощь!

И да, наконец, это дубликат …

Я думаю, ваша проблема в том, что ваши не-жадные матчи все еще могут проглотить больше, чем вы хотите, т.е. END и START s. Это похоже на работу:

 grep -Pzo '(?s)START(?:(?!END).)*?bar(?:(?!START).)*?END' file.txt 

Он охватывает все случаи в вашем примере и должен быть полным, если вы >> file.txt

 bar START test7 END 

До сих пор работает.

Я бы использовал awk, где вы можете указать разделитель записи. Если разделитель записи «END» (в отдельной строке), тогда найдите запись, содержащую «bar»:

 awk 'BEGIN {RS = ORS = "\nEND\n"} /bar/' file.txt 

Обработка текста, который появляется между марками START и END. Это изменение кажется взломанным, но оно работает для этого сценария: используя END в качестве разделителя записей, удалите любой текст перед ключевым словом START

 awk ' BEGIN {RS = ORS = "\nEND\n"} {sub(/^.*\nSTART\n/, "START\n")} /bar/ ' file.txt 

Это может не дать желаемых результатов, если «СТАРТ» может появляться более одного раза до END

 foo START hello START bar world END baz 

будет выводиться как

 START bar world END 
 perl -nE 'BEGIN {$/="\nEND\n"} say /(START.*test.*)/s' 

Как указывает @bobbel, замените say print чтобы избежать пустых разделителей строк.