如何使用grep跨多行查找模式?
在使用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的这篇教程对于将这个想法重新应用到我自己的用途非常有帮助。
如何使用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 -z
或grep -zo
,它会添加一个尾随的空字符。您可以使用tr
命令将其删除,请参阅讨论stackoverflow.com/a/7167115/32453,但仍然有点麻烦
您可以在OS X中使用brew install grep
,然后使用ggrep
命令。
如何使用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"的问题。