为什么 grep 对 '[D]ebug' 字符串的处理方式不同?

ved*_*edg 4 shell grep regular-expression wildcards

我创建了一个名为“T”的简单文本文件来测试以下异常行为grep

    1 Debug
    2 debug
    3 determined
    4 Determined
Run Code Online (Sandbox Code Playgroud)

尝试了不同的语法:

    $ grep De T
        1 Debug
        4 Determined
    $ grep de T
        2 debug
        3 determined
    $ grep Determined T
        4 Determined
    $ grep determined T
        3 determined
    $ grep Debug T
        1 Debug
    $ grep debug T
        2 debug
    $ grep [D]ebug T          # Why result is 2-nd line???
        2 debug
    $ grep [Dd]ebug T         # Why result is only one 2-nd line???
        2 debug
    $ grep [Dd]e T
        1 Debug
        2 debug
        3 determined
        4 Determined
    $ grep [d]e T
        2 debug
        3 determined
    $ grep [d]ebug T
        2 debug
    $ grep "[D]ebug" T
        1 Debug
    $ grep "[Dd]ebug" T
        1 Debug
        2 debug
    $ grep [\D]ebug T         # Why result is 2-nd line???
        2 debug
    $ grep --version
        grep (GNU grep) 2.16
Run Code Online (Sandbox Code Playgroud)

正如你可以看到,几乎每一个grep的调用返回正确的结果,但是$ grep [D]ebug T$ grep [Dd]ebug T$ grep [\D]ebug T返回错误的结果。为什么会这样?

小智 7

我猜你可能debug在当前工作目录中有一个文件或目录:

 $ ls -l
total 8
-rw-r--r--   1 jay   wheel   58 Feb  1 05:01 T
 $ grep [D]ebug T
    1 Debug
 $ grep [Dd]ebug T
    1 Debug
    2 debug

 $ touch debug
 $ ls -l
total 8
-rw-r--r--  1 jay  wheel  58 Feb  1 05:01 T
-rw-r--r--  1 jay  wheel   0 Feb  1 05:05 debug

 $ grep [D]ebug T
    2 debug
 $ grep [Dd]ebug T
    2 debug
Run Code Online (Sandbox Code Playgroud)

我向你推荐了为什么你必须总是转义 shell 元字符的这个很好的说明。

更新以澄清正在发生的事情:我假设您像我一样使用具有不区分大小写的文件系统(例如 Mac)的操作系统。当您执行该命令时,您的 shell 在实际执行grep. 其中之一是文件名扩展,其中方括号提供替代:

[Dd]ebug区分大小写的文件系统上将扩展为Debug debug,Debugdebug取决于它可以匹配的文件。由于它只匹配 file debug,您的命令变为:

grep debug T
Run Code Online (Sandbox Code Playgroud)

如果您删除该文件并执行touch Debug,您将看到命令的输出更改,因为它将被插入为

grep Debug T
Run Code Online (Sandbox Code Playgroud)

如果debug您的目录中没有该文件,您的 shell 会尝试插入括号,但在没有匹配的情况下失败,因此它碰巧传递参数不变。