如何使用grep跨多行查找模式?

34 浏览
0 Comments

如何使用grep跨多行查找模式?

我想要找到文件中按顺序包含“abc”和“efg”的文件,并且这两个字符串在文件的不同行中。例如:一个具有以下内容的文件:\n

blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..

\n应该匹配。

0
0 Comments

在使用grep命令时,如何跨多行查找模式?

某些情况下可能无法使用grep实现,但是sed非常容易实现:

sed -e '/abc/,/efg/!d' [file-with-content]

这不是查找文件,而是返回单个文件中匹配的部分。请问这个命令是什么意思?我熟悉sed,但是从未见过这样的表达式。

在sed的man手册的地址部分有详细说明。需要明确/abc/和/efg/是一个地址。

如果这个答案有更多的解释,我觉得会更有帮助。在这种情况下,我会再次点赞。我了解一点sed,但是在折腾了半个小时之后,不足以使用这个答案生成有意义的退出代码。提示:在StackOverflow上,“RTFM”很少能得到赞同,正如你之前的评论所示。

同意,解释会更好。

通过示例快速解释一下:sed '1,5d':删除1到5行之间的行。sed '1,5!d':删除不在1到5行之间的行(即保留这些行)。然后,可以使用/pattern/来搜索行号,而不是数字。还可以参考下面更简单的示例:sed -n '/abc/,/efg/p'。p是打印的意思,而-n标志不显示所有行。

这个答案是错误的;因为你只使用了第一行和最后一行,它匹配了比问题要求的更多内容。

用我自己的话来说:上述命令告诉sed删除除了范围内包含以"abc"开头到包含"efg"结尾的行之外的所有其他行。!d是为了反转匹配,所以d(删除)将删除其余的行。/abc/,/efg/是由两个模式搜索组成的范围。

如何在输出中排除/efg/?

sed -e '/abc/,/efg/!d' | tail -n+2 | sed -e '$ d'

我发现Bruce Barnett的这篇教程对于将这个想法重新应用到我自己的用途非常有帮助。

0
0 Comments

如何使用grep查找多行中的模式?

在这里,有一个受这个答案启发的解决方案:

  • 如果'abc'和'efg'可以在同一行上:

      grep -zl 'abc.*efg' <your list of files>
    

  • 如果'abc'和'efg'必须在不同的行上:

      grep -Pzl '(?s)abc.*\n.*efg' <your list of files>
    

参数:

  • -P 使用Perl兼容的正则表达式(PCRE)。

  • -z 将输入视为一组以零字节而不是换行符终止的行。即grep将输入视为一行。注意,如果不使用-l,它将显示匹配项后跟一个NUL字符,请参阅注释。

  • -l 仅列出匹配的文件名。

  • (?s) 激活PCRE_DOTALL,表示'.'可以匹配任何字符或换行符。

不,我认为这只是一个小写的l。据我所知,没有-1选项。

看起来你是对的,也许我在测试时打错了字。无论如何,对于引起误导,我向你道歉。

这很好。我只有一个关于这个的问题。如果-z选项指定grep将换行符视为零字节字符,那么为什么我们在正则表达式中还需要(?s)?如果它已经是一个非换行符字符,.直接就能匹配它了,对吧?

-z(又名--null-data)和(?s)正是您需要使用标准grep来匹配多行的内容。MacOS用户,请在评论中提及您的系统是否支持-z--null-data选项!

MacOS上肯定没有-z选项

只有这个需要特定顺序的两个模式,对吗?(可以通过使用-E和'abc.*efg|efg.*abc'来修复这个问题。)

您可以在MacOS上安装GNU Grep

请注意,使用这种方法,如果您尝试查看匹配项grep -zgrep -zo,它会添加一个尾随的空字符。您可以使用tr命令将其删除,请参阅讨论stackoverflow.com/a/7167115/32453,但仍然有点麻烦

您可以在OS X中使用brew install grep,然后使用ggrep命令。

0
0 Comments

如何使用grep查找跨多行的模式?

在处理这种操作时,Grep是一个笨拙的工具。大多数现代Linux系统中都可以使用pcregrep来执行此操作。可以使用以下命令:

pcregrep -M 'abc.*(\n|.)*efg' test.txt

其中,-M和--multiline允许模式匹配多行。

还有一个较新的pcre2grep。这两个工具都由PCRE项目提供。

在Mac OS X上,可以通过Mac Ports安装pcre2grep,命令如下:

% sudo port install pcre2

也可以通过Homebrew安装,命令如下:

% brew install pcre

或者安装pcre2:

% brew install pcre2

在Linux(Ubuntu 18.04+)上也可以安装pcre2grep:

$ sudo apt install pcre2-utils # PCRE2

$ sudo apt install pcregrep # Older PCRE

-M或--multiline选项允许模式匹配多行。

需要注意的是,.*(\n|.)*等价于(\n|.)*,后者更短。而且在我的系统上,运行较长版本时会出现"pcre_exec() error -8"的错误。因此,尝试使用'abc(\n|.)*efg'代替!

对我来说,这个模式从包含"abc"的行匹配到最后一行包含"efg"的行。如何告诉它在第一个出现的"efg"处停止匹配?

在这种情况下,需要使表达式非贪婪,例如:'abc.*(\n|.)*?efg'。也可以省略第一个.*,写成'abc(\n|.)*?efg',使正则表达式更简短(严谨起见)。

如果遇到问题,可以像这样写:([misc]|\n)*。

今天我学到了pcregrep。谢谢!

pcregrep确实使事情变得更简单,但grep也可以工作。例如,可以参考stackoverflow.com/a/7167115/123695。

在MacPorts的包pcre下,也可以在Darwin上使用。

我有一个文件,在单个文件中有多个这样的模式。我遇到了错误并得到了输出:pcregrep:Too many errors - abandoned。pcregrep:Error -8、-21或-27表示超过了资源限制。pcregrep:检查正则表达式是否存在嵌套的无限循环。

你可以以某种方式分享该文件吗?

我刚刚尝试了pcregrep,唯一的问题是它的内存消耗太快,然后就放弃了搜索。在它最后终于为我工作之前,我不得不手动设置buffer-size(比如--buffer-size=1024000)。

如何在CentOS上安装它?我在谷歌上没有找到有用的信息。

在Linux上,Ubuntu 18.04提供了pcre2grep,可以通过pcre2-utils安装。

CentOS 7提供了pcregrep实用程序,位于pcre-tools软件包中,供参考。

如果处理大于内存的文件,应该使用pcre2grep,以避免出现"grep: memory exhausted"的问题。

0