我如何grep多行上的多个模式?


Answers:


14

更新了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

您也可以使用\Knotify代替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]匹配空白或非空白的任何字符。

并且不包含“ 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行为已更改

注意:

^指向行的开头并$指向行的结尾。如果它们单独排成一行,则将它们添加到“开始”和“结束”之间以匹配它们。
我逃过了两个命令,$因为它也用于“命令替换”($(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.

将您的grep更改grep -Pzo "(?<=begin\n)(.|\n)*(?=\nend)" file为不打印\n开始行上存在的字符。
阿维纳什·拉吉

使用DOTALL修饰符做出点甚至还匹配换行字符grep -Pzo "(?s)begin.*?end" file
阿维纳什·拉吉

或者干脆,grep -Pzo "begin[\s\S]*?end" file
阿维纳什·拉吉

1
解决方案不起作用。它产生一个错误:错误grep: ein nicht geschütztes ^ oder $ wird mit -Pz nicht unterstützt的翻译是这样的:grep: a not protected ^ or $ is not supported with -Pz
musbach

1
是的,我知道,这就是您的答案。我敢肯定,当您发布此内容时,它可以正常工作,但是今天请重试。的行为grep似乎已改变。
terdon

2

如果您grep不支持perl语法(-P),则可以尝试加入这些行,匹配该模式,然后如下所示再次扩展这些行:

$ tr '\n' , < foo.txt | grep -o "begin.*end" | tr , '\n'
begin
Some text goes here.
end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.