可能重复:
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"
然而,这只是永远运行。请问有人能帮助我正确的语法吗?
答案 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。
的方法调用