如何在文件中搜索多行模式?


128

我需要找到所有包含特定字符串模式的文件。我想到的第一个解决方案是使用通过xargs grep传递的find

find . -iname '*.py' | xargs grep -e 'YOUR_PATTERN'

但是,如果我需要找到跨越多条线的模式,则会陷入困境,因为vanilla grep无法找到多线模式。



2
这个年龄较大,所以我想说这不是重复的:)
rogerdpack

@rogerdpack在将问题标记为重复项时,在回答的数量和质量以及问题的质量之后,问题的年龄是一个第三级的问题。
人间

Answers:


98

因此,我发现pcregrep代表Perl兼容正则表达式GREP

例如,您需要找到文件中_name变量后紧跟_description变量的文件:

find . -iname '*.py' | xargs pcregrep -M '_name.*\n.*_description'

提示:您需要在模式中包括换行符。根据您的平台,它可能是'\ n',\ r','\ r \ n',...


7
如下面的halka所述,“如果在正则表达式中添加(?s),您也可以说服点通配符匹配换行符”。然后通过添加-P将grep与perl regex一起使用。找 。-exec grep -nHP'(?s)SELECT。{1,60} FROM。{1,20} table_name''{}'\;
吉姆(Jim)

8
pcregrep可在Mac上使用brew install pcre
Jared Beck

1
更好的是:也可以使用-H哪一个在每次匹配之前打印文件名:pcregrep -HM
Ciro Santilli郝海东冠状病六四事件法轮功

97

你为什么不去awk

awk '/Start pattern/,/End pattern/' filename

2
这是awk大多数* nix系统随附的更容易理解和使用的方法。
阿里·卡尔巴西

24
真好!有没有办法使这场比赛不贪心?
marcin 2012年

3
只有匹配时您才如何打印文件名?
bibstha 2012年

2
您可以使用来显示比赛的行号awk '/Start pattern/,/End pattern/ {printf NR " "; print}' filename。您可以通过将行号设置为固定宽度来使其更漂亮awk '/Start pattern/,/End pattern/ {printf "%-4s ", NR; print}' filename
罗伯特

这似乎可以在单个文件上很好地工作,但是,如果我想在多个文件中搜索怎么办?
Jinstrong

84

这是使用GNUgrep的示例:

grep -Pzo '_name.*\n.*_description'

-z/ --null-data将输入和输出数据视为行序列。

请看这里


1
我认为,这仅占一个换行符。
Cloud

1
我无法使用grep进行多行搜索,而不使用标志,-z因此它不会在单行上拆分搜索,并且-o仅打印匹配的部分。
bbaja42

我发现-o导致它什么都不打印,但是-l设法获取了文件列表(我的命令是grep -rzl pattern *,-rzo无效)
Benubird13

5
对于非ASCII文件,我建议使用“ grep -Pazo ”而不是“ -Pzo”。更好是因为非ASCII文件上的-z开关可能会触发grep的“二进制数据”行为,从而改变返回值。开关''-a | --text''可以防止这种情况。
rloth

在安装了git的Mac上无法使用brew reinstall --with-pcre git
Quanlong 2015年

21

grep -P还采用libpcre,但很多更广泛安装。要查找titlehtml文档的完整部分,即使它跨越多行,也可以使用以下命令:

grep -P '(?s)<title>.*</title>' example.html

由于PCRE项目实现了perl标准,因此请使用perl文档作为参考:


嗯,刚才尝试了一下,似乎没有用... gist.github.com/rdp/0286d91624930bd11d0169d6a6337c33
rogerdpack

我不知道grep有这个选项。可能是由于以下原因:这是高度实验性的,grep -P可能会警告未实现的功能。; 那是在CentOS 7下。在Fedora 29下:这是实验性的,grep -P可能会警告未实现的功能。当然,在BSD grep中根本不存在。如果它不是那么试验性的话,那会很好,但值得提醒的是,尽管我很可能会使用它。
Pryftan

17

这是一个更有用的示例:

pcregrep -Mi "<title>(.*\n){0,5}</title>" afile.html

即使它跨越多达5行,它也会在html文件中搜索标题标签。

这是无限行的示例:

pcregrep -Mi "(?s)<title>.*</title>" example.html 

4
谢谢你 我被困在没有意识到通配符与换行符不匹配的情况。
马特

7
@matt:如果您添加(?s)正则表达式,也可以说服点通配符匹配换行符,如下所示:"(?s)<html>.*</html>"
lubomir.brindza 2011年

@matt当然,您可以检查$(在模式的末尾)以表示它是该行的末尾-尽管这与帮助您找到多个线型不同。另请参阅glob(7)。:您也可能会发现这个网站的兴趣regular-expressions.info
Pryftan


4

您可以在此处使用grep替代筛选器(免责声明:我是作者)。

它支持多行匹配,开箱即用地将搜索限制为特定文件类型:

sift -m-文件'* .py''YOUR_PATTERN'

(在所有* .py文件中搜索指定的多行正则表达式模式)

它适用于所有主要操作系统。看一下样本页面,看看如何将其用于从XML文件提取多行值。



2

@Marcin:awk非贪婪示例:

awk '{if ($0 ~ /Start pattern/) {triggered=1;}if (triggered) {print; if ($0 ~ /End pattern/) { exit;}}}' filename


1

使用ex/ vi编辑器和globstar选项(类似于awk和的语法sed):

ex +"/string1/,/string3/p" -R -scq! file.txt

aaa起点是哪里,bbb终点是哪里。

要进行递归搜索,请尝试:

ex +"/aaa/,/bbb/p" -scq! **/*.py

注意:要启用**语法,请运行shopt -s globstar(Bash 4或zsh)。

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.