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

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

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

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' 

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

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

3 Solutions collect form web for “захватить текст по шаблону с началом и конечным тегом в нескольких строках”

Я думаю, ваша проблема в том, что ваши не-жадные матчи все еще могут проглотить больше, чем вы хотите, т.е. 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 чтобы избежать пустых разделителей строк.

  • Текст цензора с регулярным выражением
  • Удалить все до «/» на каждой строке
  • Как заменить текст в столбце
  • Перемещайте каждую строку до конца строки, содержащей символ
  • Как извлечь сходство между двумя строками
  • bash regex для поиска и сохранения строки из файла
  • Расширение списка, разделенного запятыми, на отдельные строки
  • Изменение существующего файла непосредственно для замены «foo» на «bar» ТОЛЬКО для строк, содержащих «baz»,
  • Как удалить строки, соответствующие foo, но не соответствующие строке?
  • Удаление повторяющихся слов между скобками inline
  • Извлечение определенных строк набора, соответствующих правилу
  • исключить строки из файла на основе определенных значений в определенных столбцах
  • Linux и Unix - лучшая ОС в мире.