多个字符串的负前瞻

dot*_*hen 5 grep centos regular-expression

我需要找到的惯例短打开标签的PHP文件,这意味着匹配<?而不是<?php<?xml<?=。在大多数正则表达式中,这将是这样的:

 <\?(?!php|xml|=)
Run Code Online (Sandbox Code Playgroud)

然而,下面的线相匹配的不希望的<?php<?xml以及<?=部分:

$ grep -r -E "<\?(?\!php|=|xml)" *
Run Code Online (Sandbox Code Playgroud)

我已经尝试了许多反斜杠-P-e标志的排列。如何在 GNU grep 中正确使用负前瞻?

CentOS 7.3(KDE 桌面)、GNU grep 2.20(在线文档适用于 3.0,但我在man本地有)、Nescafé Decaff(这实际上可能是真正的问题)。

thr*_*rig 9

你需要-P为PCRE它实现了Perl的(?!...)负先行,并没有逃脱!(?!...)

-bash-4.2$ cat input
<?php
<?xml
<?=
<?okay
<?
-bash-4.2$ grep -P '<\?(?!php|xml|=)' input
<?okay
<?
-bash-4.2$ 
Run Code Online (Sandbox Code Playgroud)

"<\?(?\!php|=|xml)"不正确,因为这传递(?\!...)给正则表达式引擎,grep并且?\!完全不是?!正则表达式引擎;如果您不确定 shell 传递给程序的内容,请编写一些代码来检查:

$ perl -E 'printf "%*vd\n","\t",$ARGV[0];say join "\t",split //,$ARGV[0]' "?\!"
63  92  33
?   \   !
$ 
Run Code Online (Sandbox Code Playgroud)

或者使用类似的东西strace来看看得到了什么grep

-bash-4.2$ strace -o grep grep "?\!grep" /etc/passwd
-bash-4.2$ grep grep grep
execve("/usr/bin/grep", ["grep", "?\\!grep", "/etc/passwd"], [/* 24 vars */]) = 0
-bash-4.2$ 
Run Code Online (Sandbox Code Playgroud)