【问题标题】:How can I search for a multiline pattern in a file?如何在文件中搜索多行模式?
【发布时间】:2010-09-14 05:46:59
【问题描述】:

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

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

但是,如果我需要查找跨越多行的模式,我会遇到困难,因为 vanilla grep 无法找到多行模式。

【问题讨论】:

  • 这个比较老,所以我会说它不是重复的 :)
  • @rogerdpack 将问题标记为重复问题时,问题的年龄是第三个问题,仅次于答案的数量和质量以及问题的质量。
  • 有道理,投票结束,因为它是“现在重复”

标签: linux command-line grep find pcregrep


【解决方案1】:

你为什么不去awk

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

【讨论】:

  • 这更容易理解并使用大多数 *nix 系统附带的awk
  • 不错!有没有办法让这个匹配不贪心?
  • 如何只在匹配时打印文件名?
  • 你可以用awk '/Start pattern/,/End pattern/ {printf NR " "; print}' filename显示匹配的行号。您可以通过为行号指定固定宽度来使其更漂亮:awk '/Start pattern/,/End pattern/ {printf "%-4s ", NR; print}' filename
  • 这似乎在单个文件上工作得很好,但是,如果我想在多个文件中搜索呢?
【解决方案2】:

所以我发现了pcregrep,它代表Perl Compatible Regular Expressions GREP

-M 选项可以搜索跨越行边界的模式。

例如,您需要查找“_name”变量在下一行后跟“_description”变量的文件:

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

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

【讨论】:

  • 正如下面 halka 所提到的,“如果在正则表达式中添加 (?s),您也可以说服点通配符匹配换行符”。然后通过添加 -P 将 grep 与 perl 正则表达式一起使用。找 。 -exec grep -nHP '(?s)SELECT.{1,60}FROM.{1,20}table_name' '{}' \;
  • pcregrep 在 Mac 上可用brew install pcre
  • 更好:也使用-H,它会在每次匹配之前打印文件名:pcregrep -HM
  • pcregrep: line 1 of file /dev/fd/63 is too long for the internal buffer 作用于像<(cat file.txt | tr '\0' '\n') 这样的简单文本文件时。
【解决方案3】:

这里是使用GNU grep的例子:

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

-z/--null-data 将输入视为一组行,每行以零字节(ASCII NUL 字符)而不是换行符结束。

这具有将整个文件视为一大行的效果。 见说明here

【讨论】:

  • 我认为这只占一个换行符。
  • 我不能使用 grep 进行多行搜索,没有使用标志 -z 所以它不会在单行上拆分搜索,-o 只打印匹配的部分。
  • 我发现 -o 导致它不打印任何东西,但 -l 努力获取文件列表(我的命令是 grep -rzl pattern *,-rzo 不起作用)
  • 对于非 ASCII 文件,我建议使用 ''grep -Pazo'' 而不是 ''-Pzo''。更好的是,非 ASCII 文件上的 -z 开关可能会触发 grep 的“二进制数据”行为,该行为会更改返回值。切换''-a | --text'' 防止这种情况发生。
  • brew reinstall --with-pcre git安装了 git 的 Mac 上不工作
【解决方案4】:

grep -P 也使用 libpcre,但安装范围更广更多。要查找 html 文档的完整 title 部分,即使它跨越多行,您也可以使用:

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

由于the PCRE project 实现了 perl 标准,请参考 perl 文档:

【讨论】:

  • 嗯,刚才试过了,好像没用...gist.github.com/rdp/0286d91624930bd11d0169d6a6337c33
  • 我不知道 grep 有这个选项。可能是因为这个:这是高度实验性的, grep -P 可能会警告未实现的功能。;这是在 CentOS 7 下。在 Fedora 29 下:这是实验性的, grep -P 可能会警告未实现的功能。当然,在 BSD grep 中它根本不存在。如果它不是那么实验性的话会很好,但很高兴被提醒它 - 虽然我可能会使用它。
  • grep -Pzo 一起使用(尽管添加了一个尾随 NUL 字符,请参阅其他一些答案)。 grep -P 在“linux”中很常见,但在 BSD 中不常见...
【解决方案5】:

这是一个更有用的例子:

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

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

这是一个无限行的例子:

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

【讨论】:

  • 感谢您。我没有意识到通配符与换行符不匹配。
  • @matt:如果将(?s) 添加到正则表达式中,也可以说服点通配符匹配换行符,如下所示:"(?s)&lt;html&gt;.*&lt;/html&gt;"
  • @matt 当然,您可以检查 $ (在模式的末尾)以表示它是行尾 - 尽管这与帮助您找到多种线型。另请参阅 glob(7)。您可能还会发现这个网站感兴趣:regular-expressions.info
【解决方案6】:

silver searcher:

ag 'abc.*(\n|.)*efg'

银牌搜索器的速度优化可能会在这里大放异彩。

【讨论】:

    【解决方案7】:

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

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

    sift -m --files '*.py' 'YOUR_PATTERN'

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

    它适用于所有主要操作系统。查看samples page,了解如何使用它从 XML 文件中提取多行值。

    【讨论】:

      【解决方案8】:

      @马辛: awk 示例非贪婪:

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

      【讨论】:

        【解决方案9】:
        perl -ne 'print if (/begin pattern/../end pattern/)' filename
        

        【讨论】:

        • 这会打印整个文件
        • 这对我有用,只是我需要的块,在 OS X 上。
        【解决方案10】:

        这个答案可能有用:

        Regex (grep) for multi-line search needed

        要递归查找,您可以使用标志 -R(递归)和 --include(GLOB 模式)。见:

        Use grep --exclude/--include syntax to not grep through certain files

        【讨论】:

        【解决方案11】:

        使用ex/vi编辑器和globstar option(语法类似于awksed):

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

        aaa 是您的起点,bbb 是您的结束文本。

        要递归搜索,请尝试:

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

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

        【讨论】:

          猜你喜欢
          • 2022-10-14
          • 1970-01-01
          • 1970-01-01
          • 2012-09-27
          • 1970-01-01
          • 2023-03-26
          • 1970-01-01
          • 2014-11-23
          • 1970-01-01
          相关资源
          最近更新 更多