Zsh 将字符串视为文件名模式并对此提出抱怨(NOMATCH 选项)

Zsh 将字符串视为文件名模式并对此提出抱怨(NOMATCH 选项)

我正在尝试使用 Zsh,而不是 Bash。我有点不明白为什么 Zsh 会抱怨 grep 正则表达式。

usr@rk1 ~ % tty | grep ^/dev/tty[1-7]$ > /dev/null 2>&1
zsh: no matches found: ^/dev/tty[1-7]$

我注意到输出消失了,如果(1)我将正则表达式括在引号内,(2)从正则表达式中删除斜杠,或者(3)使用,那么一切都会很好setopt NO_NOMATCH

来自 zshoptions 手册:

不匹配 (+3) <C><Z>

如果文件名生成模式没有匹配项,则打印错误,而不是将其保留在参数列表中不变。这也适用于以“~”或“=”开头的文件扩展。

因此,在我看来,由于斜杠的存在,正则表达式被视为文件名模式。这算是正常现象还是错误?

此外,如果有类似于 GreyCat 的 Bashism 和 BashPitfalls 页面但针对 Zsh 的内容就太好了。您知道这样的资源吗?

答案1

如果您设置了该EXTENDED_GLOB选项,则该模式^something将用于生成文件名。从韋什麼意思手册页:

^x (需要设置 EXTENDED_GLOB。)匹配除模式 x 之外的任何内容。其优先级高于/,因此^foo/bar将搜索.除名./foo为 的文件之外的目录中的内容bar

因此,^/dev/tty[1-7]$尝试在当前目录的每个子目录(不排除任何内容,因为^后面直接跟着)中查找名为、、.../的文件,因为与 1 到 7 之间的范围内的一个字符完全匹配。在这种情况下,不会被视为特殊。dev/tty1$dev/tty2$dev/tty7$[1-7]$

您已经找到了解决方案,设置NO_NOMATCH(可能很危险,但我非常喜欢它,因为我懒得打字;))或引用(单引号或双引号)插入符号。

尝试处理print正在发生的事情:

$ setopt nomatch extended_glob
$ echo ^/dev/tty[1-7]$
zsh: no matches found: ^/dev/tty[1-7]$

# ^ is doing filename generation in every sub-dir
$ touch foo/dev/tty5$
$ echo ^/dev/tty[1-7]$
foo/dev/tty5$

# quote to prevent filename generation
$ echo "^/dev/tty[1-7]$"
^/dev/tty[1-7]$
$ echo '^/dev/tty[1-7]$'
^/dev/tty[1-7]$

如果没有EXTENDED_GLOB设置,插入符号将被逐字解释为普通字符。因此,引用又成了你的好朋友——这一次只有[1-7]引用会触发文件名生成:

$ setopt nomatch no_extended_glob
$ echo ^/dev/tty[1-7]$
zsh: no matches found: ^/dev/tty[1-7]$

# quote to prevent filename generation
$ echo ^/dev/tty"[1-7]"$
^/dev/tty[1-7]$

# caret is interpreted literally
$ mkdir ^/dev -p
$ touch ^/dev/tty5$
$ echo ^/dev/tty[1-7]$
^/dev/tty5$

因此,总结一下:引用正则表达式模式对我来说似乎总是一个好主意——尽管我通常也会尝试节省一些击键。

相关内容