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

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

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

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' 

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

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

  • Удалить все до «/» на каждой строке
  • исключить строки из файла на основе определенных значений в определенных столбцах
  • Regex, который будет grep-номера после определенной строки
  • Поиск текста между двумя конкретными символами или строками
  • Как вы можете объединить все строки, которые заканчиваются символом обратной косой черты?
  • Извлечение определенных строк набора, соответствующих правилу
  • Как заменить текст в столбце
  • Команда командной строки для добавления пробела к регулярному выражению
  • 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 чтобы избежать пустых разделителей строк.

    Linux и Unix - лучшая ОС в мире.