我正在运行一个grep找到任何*。sql文件,其中包含单词select、单词customerName和单词from。这个选择语句可以跨越许多行,并且可以包含制表符和换行符。
我尝试了以下几种方法:
$ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0-
9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from"
然而,它会一直运行下去。有人能帮我正确的语法吗?
您的基本问题是grep一次处理一行—因此它无法找到跨行分布的SELECT语句。
第二个问题是,您使用的正则表达式没有处理SELECT和FROM之间可能出现的内容的复杂性——特别是,它省略了逗号、句号(句点)和空格,但也省略了引号和任何可以在带引号的字符串内的内容。
我可能会使用基于Perl的解决方案,让Perl每次读取“段落”,并对其应用正则表达式。缺点是必须处理递归搜索——当然,有一些模块可以做到这一点,包括核心模块File::Find。
在大纲中,对于单个文件:
$/ = "\n\n"; # Paragraphs
while (<>)
{
if ($_ =~ m/SELECT.*customerName.*FROM/mi)
{
printf file name
go to next file
}
}
这需要包装成一个子,然后由File::Find的方法调用。
不需要安装grep变体pcregrep,您可以使用grep执行多行搜索。
$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c
解释:
为grep激活perl-regexp(正则表达式的强大扩展)
-z将输入视为一组行,每一行以0字节(ASCII NUL字符)结束,而不是换行符。也就是说,grep知道行的端点在哪里,但将输入视为一行。注意,如果与-o一起使用,还会添加一个尾随NUL字符,请参阅注释。
-o只打印匹配。因为我们使用的是-z,整个文件就像一个大行,所以如果有匹配,整个文件将被打印;这样就不会这样了。
在正则表达式:
(?s)激活PCRE_DOTALL,这意味着。查找任意字符或换行符
\N发现任何除了换行,即使PCRE_DOTALL激活
. * ?找到。在非贪婪模式下,即尽快停止。
^找到行开始
\1对第一组的反向引用(\s*)。这是一种尝试寻找相同缩进的方法。
可以想象,这个搜索将主方法打印在C (*. C)源文件中。