此问题在此处已有答案:
How can I search for a multiline pattern in a file?(13个回答)
两年前关闭。
我正在运行一个grep
来查找任何包含单词select
、单词customerName
和单词from
的 *.sql文件。这个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条答案
按热度按时间guykilcj1#
不需要安装grep变体
pcregrep
,您可以使用grep进行多行搜索。字符串
说明:
-P
为grep激活perl-regexp(正则表达式的强大扩展)-z
将输入视为一组行,每行以零字节(ASCII NUL字符)而不是换行符结束。也就是说,grep知道行的结尾在哪里,但将输入视为一个大行。注意,如果与-o
一起使用,这也会添加一个尾随NUL字符,请参阅注解。-o
只打印匹配项。因为我们使用的是-z
,所以整个文件就像一个大行,所以如果有匹配项,整个文件就会被打印出来;这样就不会这样做了。在regexp中:
(?s)
激活PCRE_DOTALL
,这意味着.
查找任何字符或换行符\N
查找除换行符以外的任何内容,即使激活了PCRE_DOTALL
.*?
在非贪婪模式下查找.
,即尽快停止。^
查找行首\1
反向引用到第一组(\s*
)。这是一个尝试寻找相同缩进的方法。可以想象,这个搜索将打印C(
*.c
)源文件中的main方法。sshcrbum2#
我不是很擅长grep。但是你的问题可以用AWK命令解决。看看
字符串
上面的代码将从第一次出现
select
到第一个from
序列产生。现在你需要验证返回的语句是否有customername
。为此,你可以管道结果。并且可以再次使用awk或grep。4sup72z83#
您的根本问题是
grep
一次只能运行一行--因此它无法找到跨行分布的SELECT语句。你的第二个问题是,你使用的正则表达式没有处理SELECT和FROM之间可能出现的复杂性-特别是,它省略了逗号,句号(句号)和空格,但也省略了引号和任何可以在引号字符串中出现的东西。
我可能会使用基于Perl的解决方案,让Perl一次读取“段落”,并对其应用正则表达式。缺点是必须处理递归搜索-当然,有模块可以做到这一点,包括核心模块File::Find。
概括地说,对于单个文件:
字符串
它需要被 Package 到一个sub中,然后由File::Find的方法调用。