Grep正则表达式不包含字符串


181

我正在传递正则表达式模式列表grep以检查syslog文件。它们通常与IP地址和日志条目匹配;

grep "1\.2\.3\.4.*Has exploded" syslog.log

这只是"1\.2\.3\.4.*Has exploded"循环中要传递的部分的模式列表,例如,我不能传递“ -v”。

我很困惑尝试执行上述操作,不匹配具有特定IP地址和错误的行,因此“!1.2.3.4。*已爆炸”将匹配syslog行,而不是1.2.3.4,告诉我它已爆炸。我必须能够包含不匹配的IP。

我在StackOverflor上看到了许多类似的帖子,但是他们使用了我似乎无法使用的正则表达式模式grep。谁能提供一个可行的例子grep

更新: 这是在这样的脚本中发生的;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done

您是说有时要匹配某个模式,而其他时候想要匹配某个模式以外的所有内容吗?(这似乎是一个奇怪的要求,但无论如何)。在这种情况下,为什么不遍历两个不同的模式列表?
Beerbajay 2012年

我对正则表达式不是很了解。我不想为“ Has Exploded”使用grep,因为我不想对每个日志记录设备都了解这一点,所以我可以在某条语句中以某种方式为“ Has Exploded”和!9.10.11.12进行grep吗?
jwbensley,2012年

如果您绝对必须在一项声明中做到这一点,那么正如Neil所建议的那样,消极后顾之忧是必经之路。看到我的评论在那里。
Beerbajay 2012年

根据@Neil的答案,使用PCRE样式的正则表达式匹配和否定的超前断言:默认情况下,对PCRE进行patterns[3]="\!9\.10\.11\.12.*Has exploded"更改 patterns[3]="(?<!9\.10\.11\.12).*Has exploded"grep "${patterns[$i]}" logfile.log更改会 grep -P "${patterns[$i]}" logfile.log假定使用更多的元字符,因此某些转义符可能需要从其他匹配表达式中删除。
Codex24

Answers:


340

grep匹配,grep -v取反。如果您需要“匹配A但不匹配B”,则通常使用管道:

grep "${PATT}" file | grep -v "${NOTPATT}"

正如我提到的那样,这已经进入了循环的中间,我只是将PATTERN传递给grep,所以我不能像我提到的那样使用“ -v”。我只是遍历PATTERN列表并传递给grep。
jwbensley

1
您确实-v可以使用,并且可以循环使用它。也许您需要更加具体地说明自己的局限性,或者您可能对脚本的工作方式有误解。尝试发布一些代码。
Beerbajay 2012年

谢谢Beerbajay,我在原始帖子中添加了一段代码,以提供一些上下文。你明白我的意思了吗?
jwbensley

这个答案并不完全正确,但是您几乎是在写Beerbajay,我需要重新考虑循环并最终使用-v。感谢您的指点;)
jwbensley 2012年

1
但是,如果A由B组成怎么办?换句话说,如果我想要的东西,以配合线没有一个线路与AB?管道将无法工作。
pawamoy 2015年

15
(?<!1\.2\.3\.4).*Has exploded

您需要使用-P来运行它,以使其具有负向后看(Perl正则表达式),因此命令为:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

试试这个。如果以开头,它将使用后向否定式忽略该行1.2.3.4。希望有帮助!


1
我很确定这grep不支持环顾四周。除非您使用的是Gnu grep并使用--P参数使其使用PCRE引擎。
蒂姆·皮茨克

不,grep不支持这种Regex类型。$ grep -P(?<\!1 \ .2 \ .3 \ .4)test.log -bash:语法错误,出现在意外标记`('附近
jwbensley,2012年

如果正则表达式包含可由shell解释的字符,则需要引用该正则表达式。
Beerbajay 2012年

正确的引用:grep -P '(?<!1\.2\.3\.4) Has exploded' test.log请注意,后面的查找仅适用于表达式匹配部分之前的字符,因此,如果地址和消息之间还有其他内容,例如1.2.3.4 FOO Has exploded,则此方法将无效。
Beerbajay 2012年

@TimPietzcker,非常细心。我将其添加到问题中。另外,请注意,.*由于他的示例也有一个否定的后面,因此我想中间还有其他文字。
尼尔

2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

应该与

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.