我正试图为Ui\.
未跟Line
或甚至只是L
编写正则表达式以查找特定字符串的所有实例而不是其他字符串的正确方法是什么?
使用前瞻
grep "Ui\.(?!L)" *
bash: !L: event not found
grep "Ui\.(?!(Line))" *
nothing
答案 0 :(得分:126)
负面的前瞻,这就是你所追求的,需要比标准grep
更强大的工具。您需要一个支持PCRE的grep。
如果你有GNU grep
,当前版本支持选项-P
或--perl-regexp
,然后你可以使用你想要的正则表达式。
如果您没有(最近版本的)GNU grep
,请考虑获取ack
。
答案 1 :(得分:33)
部分问题的答案就在这里,而ack的行为方式相同: Ack & negative lookahead giving errors
你正在使用grep的双引号,它允许bash“将!
解释为历史扩展命令。”
您需要将模式包装在SINGLE-QUOTES中:
grep 'Ui\.(?!L)' *
但是,请参阅@JonathanLeffler's answer以解决标准grep
中的否定前瞻问题!
答案 2 :(得分:8)
你可能无法使用grep执行标准的负向前瞻,但通常你应该能够使用" inverse"来获得相同的行为。切换' -v'。使用它你可以构建一个正则表达式,以补充你想要匹配的东西,然后通过2个greps管道。
对于有问题的正则表达式,您可能会执行类似
的操作grep 'Ui\.' * | grep -v 'Ui\.L'
答案 3 :(得分:3)
如果您需要使用不支持负前瞻的正则表达式实现并且您不介意匹配额外的字符*,那么您可以使用negated character classes [^L]
,alternation |
和end of string anchor $
在您的情况下incomparables
完成工作。
z.sorted[,!duplicated(z.sorted,MARGIN=2,incomparables=NA)]
unique(z.sorted,MARGIN=2,incomparables=NA)
匹配您感兴趣的字符串
grep 'Ui\.\([^L]\|$\)' *
匹配Ui\.
以外的任何单个字符,或者与该行的结尾匹配:\([^L]\|$\)
或L
。
如果你想排除多于一个字符,那么你只需要对它进行更多的交替和否定。要查找[^L]
后面没有$
:
a
哪一个(bc
后跟不grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *
或后跟行尾:a
然后b
或a
)或({ {1}}后跟[^b]
,后跟不是$
或后面是行尾:a
然后是b
,然后是c
或a
。
这种表达式变得相当笨拙并且即使是短字符串也容易出错。您可以编写一些内容来为您生成表达式,但是使用支持负前瞻的正则表达式实现可能更容易。
*如果您的实施支持non-capturing groups,那么您可以避免捕获额外的字符。
答案 4 :(得分:0)
如果你的grep不支持-P或--perl-regexp,你可以安装支持PCRE的grep,例如: " pcregrep",而不是像GNU grep那样需要任何命令行选项来接受Perl兼容的正则表达式,你只需要运行
pcregrep "Ui\.(?!Line)"
你不需要另一个嵌套组来" Line"如你的例子" Ui。(?!(Line))" - 外面的群体就足够了,就像我上面所示。
让我给你另一个看负面断言的例子:当你有行列表,由" ipset"返回时,每一行显示行中间的数据包数量,你不要&#39 ; t需要零包的行,你只需运行:
ipset list | pcregrep "packets(?! 0 )"
如果您喜欢与Perl兼容的正则表达式并且使用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;};}"
答案 5 :(得分:0)
至少对于在“Ui”之后不想要“L”字符的情况。你真的不需要 PCRE。
grep -E 'Ui\.($|[^L])' *
这里我确保匹配“Ui”的特殊情况。在行尾。