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