正则expression式在grep中是“未遵循”的

我试图grep所有的Ui\.实例Ui\. 没有跟随Line或甚至只是字母L

写一个正则expression式来寻找一个特定string的所有实例NOT NOT其他string的正确方法是什么?

使用lookaheads

 grep "Ui\.(?!L)" * bash: !L: event not found grep "Ui\.(?!(Line))" * nothing 

消极的向前看,这是你以后,需要比标准的grep更强大的工具。 你需要一个PCRE启用的grep。

如果你有GNU grep ,当前版本支持选项-P--perl-regexp ,然后你可以使用你想要的正则expression式。

如果你没有GNU grep (最新版本),那么考虑一下。

答案是你的问题的一部分在这里,而且Ack的行为也是一样的: Ack和负向预测错误

你使用双引号的grep,这允许bash“解释!作为历史扩展命令”。

你需要把你的模式包装在单引号中: grep 'Ui\.(?!L)' *

不过,请参阅@ JonathanLeffler的回答,以解决标准grep负向视图问题!

你可能不能使用grep来执行标准的负向预测,但通常你应该能够使用“反向”开关“-v”来获得等价的行为。 使用它你可以构造一个正则expression式来补充你想要匹配的内容,然后通过2 greps来pipe理它。

对于正在讨论的正则expression式,你可能会做类似的事情

 grep 'Ui\.' * | grep -v 'Ui\.L' 

如果您需要使用不支持负向预测的正则expression式实现,并且您不介意匹配额外的字符,则可以使用否定的字符类[^L] , 交替| ,以及string锚点$的结尾 。

在你的情况下grep 'Ui\.\([^L]\|$\)' *做这个工作。

  • Ui\. 匹配你感兴趣的string

  • \([^L]\|$\)匹配除L以外的任何单个字符,或匹配行的末尾: [^L]$

如果你想排除的不只是一个字符,那么你只需要抛弃更多的交替和否定。 要finda没有按照bc

grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *

哪一个是(后面跟着不是b或者跟在行尾之后: a then [^b]或者$ )或者( a后面跟着b ,后面跟着不是c或者跟着行尾:然后b ,然后[^c]$

这种expression式即使是一个短的string也相当笨拙,容易出错。 你可以写一些东西来为你生成expression式,但是使用支持负向预测的正则expression式可能会更容易一些。

我认为这个链接可以帮助你,首先理解正则expression式是如何工作的,其次,如何构build你的正则expression式: http : //www.regular-expressions.info/tutorialcnt.html

如果你的grep不支持-P或–perl-regexp,你可以安装启用了PCRE的grep,比如“pcregrep”,比不需要像GNU grep这样的命令行选项来接受Perl兼容的规则expression式,你只要运行

 pcregrep "Ui\.(?!Line)" 

你不需要像“Ui。(?!(Line))”那样需要另外一个嵌套的“Line”组 – 就像上面显示的那样,外部组足够了。

让我给你另外一个看负面断言的例子:当你有“ipset”返回的行列表时,每一行显示行中的数据包数量,而且你不需要零包数据行,跑:

 ipset list | pcregrep "packets(?! 0 )" 

如果你喜欢perl兼容的正则expression式,并有perl但没有pcregrep,或者你的grep不支持–perl-regexp,你可以像perl脚本一样使用像grep一样的脚本:

 perl -e "while (<>) {if (/Ui\.(?!Lines)/){print;};}" 

Perl像grep一样接受stdin,例如

 ipset list | perl -e "while (<>) {if (/packets(?! 0 )/){print;};}"