我正在尝试使用 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$
因此,总结一下:引用正则表达式模式对我来说似乎总是一个好主意——尽管我通常也会尝试节省一些击键。