Как я grep для нескольких шаблонов на нескольких строках?
Точнее
Some text
begin
Some text goes here.
end
Some more text
и я хочу извлечь весь блок, который начинается с "начала" до "конца".
с помощью awk мы можем сделать как awk '/begin/,/end/' text,
Как сделать с grep?
2 ответа
Обновлено 18 ноября 2016 г. (поскольку изменено поведение grep: grep с параметром -P теперь не поддерживает ^ а также $ якоря [в Ubuntu 16.04 с ядром v:4.4.0-21-generic])( неверное (не) исправление)
$ grep -Pzo "begin(.|\n)*\nend" file
begin
Some text goes here.
end
примечание: для других команд просто замените якоря '^' & '$' на якорь новой строки '\n'______________________________
С помощью команды grep:
grep -Pzo "^begin\$(.|\n)*^end$" file
Если вы не хотите включать шаблоны "начало" и "конец" в результат, используйте grep с поддержкой Lookbehind и Lookahead.
grep -Pzo "(?<=^begin$\n)(.|\n)*(?=\n^end$)" file
Также вы можете использовать \K уведомить вместо утверждения Lookbehind.
grep -Pzo "^begin$\n\K(.|\n)*(?=\n^end$)" file
\K опция игнорировать все до сопоставления с шаблоном и игнорировать сам шаблон.\n используется для предотвращения печати пустых строк из вывода.
Или, как предполагает @AvinashRaj, есть простой простой grep:
grep -Pzo "(?s)^begin$.*?^end$" file
grep -Pzo "^begin\$[\s\S]*?^end$" file
(?s) сообщает grep, что точка должна соответствовать символам новой строки.[\s\S] соответствует любому символу, который является пробелом или не пробелом.
И их вывод без включения "начало" и "конец" выглядит следующим образом:
grep -Pzo "^begin$\n\K[\s\S]*?(?=\n^end$)" file # or grep -Pzo "(?<=^begin$\n)[\s\S]*?(?=\n^end$)"
grep -Pzo "(?s)(?<=^begin$\n).*?(?=\n^end$)" file
смотрите полный тест всех команд здесь (устарел, поскольку поведение grep с параметром -P изменено)
Замечания:
^ указать начало линии и $ указать конец линии. они добавляются вокруг "начала" и "конца", чтобы соответствовать им, если они находятся в одной строке.
В двух командах я сбежал $ потому что он также использует для "Подстановка команд" ($(command)), который позволяет выводу команды заменить имя команды.
От человека grep:
-o, --only-matching
Print only the matched (non-empty) parts of a matching line,
with each such part on a separate output line.
-P, --perl-regexp
Interpret PATTERN as a Perl compatible regular expression (PCRE)
-z, --null-data
Treat the input as a set of lines, each terminated by a zero byte (the ASCII
NUL character) instead of a newline. Like the -Z or --null option, this option
can be used with commands like sort -z to process arbitrary file names.
Если ваш grep не поддерживает синтаксис Perl (-P), вы можете попробовать соединить линии, сопоставить их с шаблоном, а затем снова развернуть линии, как показано ниже:
$ tr '\n' , < foo.txt | grep -o "begin.*end" | tr , '\n'
begin
Some text goes here.
end