如何在多行上grep多个模式?

确切地说

Some text begin Some text goes here. end Some more text 

我想提取从“开始”到“结束”的整个块。

使用awk,我们可以像awk '/begin/,/end/' text

grep怎么办?

更新于2016年11月18日 (因为grep行为已更改:grep with -P参数现在不支持^$ anchors [在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 

如果您不希望在结果中包含“begin”和“end”模式,请将grep与Lookbehind和Lookahead支持一起使用。

 grep -Pzo "(?<=^begin$\n)(.|\n)*(?=\n^end$)" file 

您也可以使用\K notify而不是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 

请参阅此处所有命令的完整测试 ( 已更改为-p参数的grep行为已更改

注意:

^指向一行的开头, $指向一行的结尾。 这些添加到“开始”和“结束”的周围以匹配它们,如果它们在一条线上。
在两个命令中,我转义了$因为它还用于“命令替换”( $(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