转义grep

时间:2017-03-15 22:49:14

标签: regex grep

我对在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本身对文字字符串\\|做了一些特殊的事情。

4 个答案:

答案 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。在双引号中,删除后跟这些字符之一的反斜杠

这意味着您的表达式将按以下方式处理:

  1. grep -e"def|zzz" – grep收到def|zzz;因为|默认为基本正则表达式(BRE),所以它不是特殊的 1 ,并且grep尝试匹配文字字符串def|zzz
  2. grep -e"def\|zzz"|不是上述特殊字符之一,因此grep接收def\|zzz,GNU grep将\|视为交替 1 < / sup>。
  3. grep -e"def\\|zzz"\\根据手册摘录是特殊的(尝试echo "\\"); grep之所以看到def\|zzz是因为shell删除了反斜杠,并且其行为与第二种情况相同。
  4. 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,grepgrep -E之间的唯一区别是必须逃避。功能是相同的。