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

Posted

技术标签:

【中文标题】Grep 正则表达式不包含字符串【英文标题】:Grep regex NOT containing string 【发布时间】:2012-05-11 19:14:09 【问题描述】:

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

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

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

我很困惑尝试与上述相反,并且不匹配具有特定 IP 地址和错误的行,因此“!1.2.3.4.*已爆炸”将匹配 1.2.3.4 以外的任何内容的 syslog 行告诉我它爆炸了。我必须能够包含不匹配的 IP。

我在 *** 上看到过各种类似的帖子。然而,他们使用我似乎无法使用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

【问题讨论】:

你的意思是你有时想要匹配一个模式,但其他时候想要匹配所有除了某个模式? (这似乎是一个奇怪的要求,但无论如何)。在这种情况下,为什么不遍历两个不同的模式列表? 好吧,我对正则表达式不是很了解;我不想用 grep 表示“已爆炸”,因为我不想知道每个日志记录设备的情况,所以我能以某种方式在一个语句中用 grep 表示“已爆炸”和 !9.10.11.12 吗? 如果您绝对必须在一个声明中执行此操作,则正如 Neil 所建议的那样,消极的后视是要走的路。在那里查看我的评论。 使用 PCRE 风格的正则表达式匹配和否定的前瞻断言,根据 @Neil 的回答: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 PCRE 假定更多元字符默认情况下,因此可能需要从其他匹配的表达式中删除一些转义。 【参考方案1】:

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

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

【讨论】:

正如我所提到的,这将进入循环的中间,我只是将 PATTERN 传递给 grep,所以我不能像我提到的那样使用“-v”。我只是循环一个 PATTERN 列表并传递给 grep。 您确实可以使用-v,并且可以循环使用它。也许您需要更具体地了解您的限制,或者您对脚本的工作方式有误解。尝试发布一些代码。 感谢 beerbajay,我已在原始帖子中添加了一段代码以提供一些上下文。你明白我现在的意思了吗? 这个答案并不完全正确,但你几乎写了 beerbajay,我需要重新考虑循环并最终使用 -v。感谢您的指点;) 但是如果 A 由 B 组成呢?换句话说,如果我想用 no A and 用 AB 匹配行怎么办?管道不起作用。【参考方案2】:
(?<!1\.2\.3\.4).*Has exploded

你需要使用 -P 来运行它以得到否定的lookbehind(Perl 正则表达式),所以命令是:

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

试试这个。如果它前面有1.2.3.4,它会使用否定的lookbehind 来忽略该行。希望对您有所帮助!

【讨论】:

我很确定grep 不支持环视。除非您使用 Gnu grep 并使用 --P 参数使其使用 PCRE 引擎。 不,grep 不支持这种类型的正则表达式; $grep -P (? 附近的语法错误 如果正则表达式包含将由 shell 解释的字符,您将需要引用它。 正确引用:grep -P '(?&lt;!1\.2\.3\.4) Has exploded' test.log 请注意,后向仅适用于表达式匹配部分之前的字符,因此如果地址和消息之间还有其他内容,例如1.2.3.4 FOO Has exploded,这行不通。 @TimPietzcker,非常细心。我将把它添加到问题中。另外,请注意,在否定的后面有一个.*,因为他的例子也有它,我想中间可能还有其他文字。【参考方案3】:
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"    

【讨论】:

以上是关于Grep 正则表达式不包含字符串的主要内容,如果未能解决你的问题,请参考以下文章

Linux正则表达式教程:Grep Regex示例

shell脚本应用正则表达式grep,sed,awk,的应用

shell脚本应用正则表达式grep,sed,awk,的应用

grep命令

grep家族

grep