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

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

准确来说

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

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

使用 awk 我们可以做到类似的事情awk '/begin/,/end/' text

如何使用 grep?

答案1

更新于 2016 年 11 月 18 日(由于 grep 行为已更改:带有 -P 参数的 grep 现在不支持^$锚点 [在内核为 v:4.4.0-21-generic 的 Ubuntu 16.04 上])(错误(非)修复

$ grep -Pzo "begin(.|\n)*\nend" file
begin
Some text goes here.  
end

注意:对于其他命令,只需将“^”和“$”锚点替换为换行符'\n' ______________________________

使用 grep 命令:

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

如果您不想在结果中包含模式“begin”和“end”,请使用支持 Lookbehind 和 Lookahead 的 grep。

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

您还可以使用\K通知来代替后视断言。

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]匹配任何空格或非空格字符。

而不包括“begin”和“end”的输出如下:

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 行为已过时

笔记:

^指向一行的开头和$结尾。如果它们单独在一行中,则将它们添加到“begin”和“end”的周围以匹配它们。
在两个命令中我都省略了,$因为它还使用了“命令替换”( $(command)),它允许命令的输出替换命令名称。

来自 man 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.

答案2

如果您的grep不支持 perl 语法(-P),您可以尝试连接行、匹配模式,然后再次扩展行,如下所示:

$ tr '\n' , < foo.txt | grep -o "begin.*end" | tr , '\n'
begin
Some text goes here.
end

相关内容