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

时间:2010-09-15 12:56:24

标签: regex linux cygwin grep

  

可能重复:
  How can I search for a multiline pattern in a file ? Use pcregrep

我正在运行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"

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

3 个答案:

答案 0 :(得分:430)

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

$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c

说明:

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

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

-o仅打印匹配。因为我们使用-z,所以整个文件就像一个大行,所以如果匹配,则会打印整个文件;这样就不会那样做。

在regexp中:

(?s)激活PCRE_DOTALL,这意味着.找到任何字符或换行符

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

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

^找到行的开头

\1反向引用第一组(\s*)这是尝试查找方法的相同缩进

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

答案 1 :(得分:150)

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

awk '/select/,/from/' *.sql

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

答案 2 :(得分: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
     }
}

需要将其包装到一个子中,然后由File :: Find。

的方法调用