需要用于多行搜索的正则表达式(grep)

Cia*_*her 210 regex linux grep cygwin

可能重复:
如何在文件中搜索多行模式?使用pcregrep

我正在运行a grep来查找任何*.sql文件,select其后跟单词customerName后跟单词from.此select语句可以跨越多行,并且可以包含制表符和换行符.

我在下面尝试了一些变化:

$ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0-
9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from"
Run Code Online (Sandbox Code Playgroud)

然而,这只是永远运行.请问有人能帮助我正确的语法吗?

alb*_*fan 460

无需安装grep变量pcregrep,您可以使用grep进行多行搜索.

$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c
Run Code Online (Sandbox Code Playgroud)

说明:

-P 为grep激活perl-regexp(常规扩展的强大扩展)

-z在行尾压缩换行符,将其替换为空字符.也就是说,grep知道行尾的位置,但将输入视为一个大行.

-o打印只匹配.因为我们正在使用-z,整个文件就像一个大行,所以如果匹配,整个文件将被打印; 这样它就不会那样做.

在正则表达式中:

(?s)激活PCRE_DOTALL,表示.查找任何字符或换行符

\N找到除换行之外的任何内容,即使已PCRE_DOTALL激活

.*?找到非.同意模式,即尽快停止.

^ 找到行的开头

\1backreference to first group(\s*)这是尝试找到相同的方法缩进

可以想象,此搜索在C(*.c)源文件中打印main方法.

  • -zo足以满足我的多线需求,谢谢!(upvoted). (25认同)
  • / bin/grep:无法组合-P和-z选项 (14认同)
  • 我建议使用''**grep -Pazo**'而不是不用的''-Pzo''.说明:非ASCII文件上的-z开关_may_触发grep的"二进制数据"行为,它会更改返回值.切换'' - a | --text''阻止了. (9认同)
  • / bin/grep:PCRE不支持\ L,\ l,\ N,\ U或\ u (7认同)
  • 我正在使用**GNU grep 2.6.3**,捆绑在**Ubuntu 11.04**中它确实如此,你的版本是什么?@Oli? (4认同)
  • `grep:unescaped ^或$不支持-Pz` (4认同)
  • `-z`,又名。`--null-data` 将为每个匹配输出一个额外的 NUL(\x00) 字符。对于某些用例来说,这可能是一个不需要的副作用。 (4认同)
  • “正如您想象的那样,此搜索会在 C (*.c) 源文件中打印主要方法。” ......我敢大声说出来:如果你这么说...... :) (2认同)
  • 您是否有适用于无法读入内存的大文件的解决方案? (2认同)
  • 仅供参考,在OS X上,系统默认的`grep`是基于BSD而不是GNU版本.结果,PCRE(`-P`开关)遗憾地得不到支持. (2认同)
  • -z不是用“用空字符替换换行符”,而是“将输入作为一组行来处理,每行都以零字节(ASCII NUL字符)而不是换行符终止”。 (2认同)
  • 如果您需要在单独的行上匹配,则将结果通过管道传输到 `tr '\0' '\n'`! (2认同)
  • 惊人的!感谢您的发表。顺便说一句,Mac 版只需使用 `brew install grep` 然后将其与 `ggrep` 一起使用。 (2认同)

小智 160

grep我不是很好.但您的问题可以使用AWK命令解决.看看

awk '/select/,/from/' *.sql
Run Code Online (Sandbox Code Playgroud)

上面的代码将首先出现select直到第一个序列from.现在您需要验证返回的语句是否有customername.为此,您可以管道结果.并且可以再次使用awk或grep.

  • 为了完整起见:这也适用于(更简单的)sed:`sed -n '/select/,/from/p'whatever.sql` (5认同)
  • 这里的逗号有什么作用? (4认同)
  • 真棒简单的解决方案.谢谢 !@Kev逗号用作AWK _range pattern_中的分隔符.请参阅[第7.1.3节"使用AWK用户指南模式指定记录范围"中的完整说明](https://www.gnu.org/software/gawk/manual/gawk.html#Ranges) (3认同)
  • 如何获得最后一次出现呢? (2认同)
  • 我们如何做同样的事情,但不包括选择也不包括线? (2认同)

Jon*_*ler 7

你的根本问题是grep一次只能运行一行 - 所以它找不到跨行的SELECT语句.

你的第二个问题是你正在使用的正则表达式没有处理SELECT和FROM之间出现的复杂性 - 特别是它省略了逗号,句号(句点)和空格,还有引号和任何可以在里面的内容引用的字符串.

我可能会使用基于Perl的解决方案,让Perl一次读取'paragraph'并应用正则表达式.缺点是必须处理递归搜索 - 当然还有模块,包括核心模块File :: Find.

概括地说,对于单个文件:

$/ = "\n\n";    # Paragraphs

while (<>)
{
     if ($_ =~ m/SELECT.*customerName.*FROM/mi)
     {
         printf file name
         go to next file
     }
}
Run Code Online (Sandbox Code Playgroud)

这需要包装到一个sub中,然后由File :: Find的方法调用.

  • Grep 一次不能运行一行。它会在整个语料库中搜索匹配项,只有当找到匹配项时,它才会返回考虑中间是否有换行符。这样,它就不必扫描语料库来寻找新行(这会显着减慢速度) (2认同)
  • 它按行工作,但不能一次只工作一行。没有循环执行某种“(for line inlines: doesMatch(line))”。当考虑 fgrep(固定字符串)以及 boyer-moore 的工作原理时,这一点更加明显。mmap 并不真正相关 (2认同)