正则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;};}"