我对在grep的正则表达式中转义交替运算符|
需要多少反斜杠感到困惑。此
echo abcdef | grep -e"def|zzz"
什么都不输出,因为grep不在扩展的正则表达式模式下。使用一个反斜杠进行转义,
echo abcdef | grep -e"def\|zzz"
打印abcdef
。更令人惊讶的是,使用2个反斜杠进行转义也很有效,
echo abcdef | grep -e"def\\|zzz"
打印abcdef
。三个反斜杠的转义失败,
echo abcdef | grep -e"def\\\|zzz"
什么都不打印。
有没有人有解释,特别是对于2反斜杠案例?
修改
使用这个简单的参数打印程序,
void main(int argc, char** argv)
{
for (int i = 0; i < argc; i++)
printf("Arg %d: %s\n", i, argv[i]);
}
我调查了我的shell对上面命令行的作用:
-e"def|zzz"
变为-edef|zzz
-e"def\|zzz"
变为-edef\|zzz
-e"def\\|zzz"
变为-edef\\|zzz
-e"def\\\|zzz"
变为-edef\\\|zzz
因此,所有双引号都被删除,并且shell不会改变反斜杠和管道。我怀疑grep本身对文字字符串\\|
做了一些特殊的事情。
答案 0 :(得分:0)
第一个失败是因为grep以编程方式转义管道,导致正则表达式中出现 literal 管道。
最后一次尝试失败,因为\\\|
会在正则表达式中生成文字反斜杠,然后是文字管道。
echo 'def|zzz' | grep -e "def|zzz" --> def|zzz
echo 'def\\|zzz' | grep -e "def\\\|zzz" --> def\|zzz
答案 1 :(得分:0)
根据grep手册页,特别是根据信息页面,为grep提供的所有示例都包括单引号而不是双引号。
使用单引号进行一些类似的测试我们有不同的正确行为:
$ cat file1
def
def\
def\\
def\\\
def\|
aaa
nnn
$ cat -n file1 |grep -e 'def|zzz' #No results
$ cat -n file1 |grep -e 'def\|zzz'
1 def
2 def\
3 def\\
4 def\\\
5 def\|
$ cat -n file1 |grep -e 'def\\|zzz' #No results
$ cat -n file1 |grep -e 'def\\\|zzz'
2 def\
3 def\\
4 def\\\
5 def\|
$ cat -n file1 |grep -e 'def\\\\|zzz' #No results
$ cat -n file1 |grep -e 'def\\\\\|zzz'
3 def\\
4 def\\\
结论:对于grep中的正则表达式,请使用单引号。
但说实话,我不知道为什么使用双引号时行为完全不同。应该与bash扩展有关。
<强>更新强>
请参阅此bash函数测试结果,该结果证明了args中单引号和双引号的不同解释:
function tt { printf "%s: %s\n" "$1" "$2"; }
tt -e 'def\\|aaa' #Parsed correctly
tt -e 'def\\\|aaa' #We send three slashes - function gets three slashes
tt -e 'def\\\\|aaa' #We send four slashes - function gets four slashes
tt -e "def\\|aaa" #We send two slashes but function displays ONE
tt -e "def\\\|aaa" #We send three slashes but function displays TWO
tt -e "def\\\\|aaa" #We send four slashes but function displays TWO
#Output
-e: def\\|aaa
-e: def\\\|aaa
-e: def\\\\|aaa
-e: def\|aaa
-e: def\\|aaa
-e: def\\|aaa
请注意双引号内有三个和四个斜杠的情况。
更进一步:
tt -e 'def\|aaa' #Displays def\|aaa (correct parsing)
tt -e 'def\\|aaa' #Displays def\\|aaa (correct parsing)
tt -e "def\|aaa" #Displays def\|aaa (correct parsing)
tt -e "def\\|aaa" #Displays def\|aaa (same as before - not correct parsing)
上面的双引号中的最后两行可能解释了为什么测试中的结果(\|
vs \\|
)在用双引号括起时具有相同的正则表达式操作。
答案 2 :(得分:0)
小写populate : "category"
选项用于表示多个搜索操作。交替暗示:
-e
或者,您可以使用上部$ echo abcdef | grep -e 'def' -e'zzz'
abcdef
$ echo abczzz | grep -e 'def' -e'zzz'
abczzz
选项来扩展正则表达式表示法:
-E
我相信这可以直接解决您的问题(使用$ echo abcdef | grep -E 'def|zzz'
abcdef
进行更改,或使用-e
进行扩展的正则表达式表示法)。希望这会有所帮助: - )
FWIW,反斜杠的问题是-E
对bash有特殊意义,需要进行转义,除非它是单引号。以下是引用和转义规则以及常见陷阱的资源:http://wiki.bash-hackers.org/syntax/quoting
答案 3 :(得分:0)
如果用双引号括住正则表达式,则外壳treats backslashes specially(强调我的名字):
仅当反斜杠后面跟随以下字符之一时,才保留其特殊含义:
$
,`
,"
,\
或newline
。在双引号中,删除后跟这些字符之一的反斜杠。
这意味着您的表达式将按以下方式处理:
grep -e"def|zzz"
– grep收到def|zzz
;因为|
默认为基本正则表达式(BRE),所以它不是特殊的 1 ,并且grep尝试匹配文字字符串def|zzz
。grep -e"def\|zzz"
– |
不是上述特殊字符之一,因此grep接收def\|zzz
,GNU grep将\|
视为交替 1 < / sup>。grep -e"def\\|zzz"
– \\
根据手册摘录是特殊的(尝试echo "\\"
); grep之所以看到def\|zzz
是因为shell删除了反斜杠,并且其行为与第二种情况相同。grep -e"def\\\|zzz"
–外壳将其变成def\\|zzz
(\\
变成\
,\|
对外壳不是特殊的,并且保持不变) grep认为\\
是文字反斜杠(backslash escaped by backslash),因此|
并不特殊,因此grep尝试匹配确切的字符串def\|zzz
。一般来说,谨慎地用单引号括住正则表达式,以便外壳程序不理会它。
请注意,我认为您的C程序不能代表Shell如何处理参数;在Shell Operation中,quoting是一个单独的步骤,包括反斜杠处理(请参见Escape Character)。
1 作为扩展,GNU grep允许您在BRE中转义|
并进行替换。 POSIX BRE没有交替。结果,对于GNU grep,grep
和grep -E
之间的唯一区别是必须逃避。功能是相同的。