使用zsh
这两个命令会产生相同的结果:
ls (dir1|dir2)/dir3/*.txt
ls {dir1,dir2}/dir3/*.txt
仅使用bash
以下作品:
ls {dir1,dir2}/dir3/*.txt
那么,如果我想列出.txt
多个特定目录中的所有文件,使用zsh
上述选项之一是首选还是正确?或者,它们是否等效并且zsh
仅提供 中缺少的正则表达式功能bash
?
答案1
您很可能应该选择第一个版本。
(...)
是一个全局运算符,旨在生成文件名, while {...}
,称为大括号扩展,旨在生成字符串。在许多情况下,您可以在它们之间切换并获得相同的结果,因为文件名是字符串,但几乎没有什么区别。例如,考虑一个目录不存在,在这种情况下你会得到
$ ls (dir1|fakedir)/dir3/*.txt
dir1/dir3/file.txt
$ ls {dir1,fakedir}/dir3/*.txt
zsh: no matches found: fakedir/dir3/*.txt
也许您想要第一个结果。重要的是,第二种情况的错误不是来自大括号扩展,而是来自*
!如果您删除它,ls (dir1|dir1)/dir3
则ls
声称它无法访问fakedir/dir3
,因此错误是不可预测的(取决于其他内容)。
另一个区别是,第一个版本在重复目录的情况下仅产生一个输出,而第二个版本仅输出多次相同的输出:
$ ls (dir1|dir1)/dir3/*.txt
dir1/dir3/file.txt
$ ls {dir1,dir1}/dir3/*.txt
dir1/dir3/file.txt dir1/dir3/file.txt
同样,我相信在大多数情况下用户想要第一个结果。
如果您想完全控制通配机制,我建议您熟悉全局限定符(看man zshexpn
)。
如果是bash
这样,最好设置extglob
选项,让您可以访问更多的全局变量,虽然不如 强大zsh
,但仍然比大括号扩展更好。
zsh
具体来说, s (foo|bar)
in的等价物bash -O extglob
是@(foo|bar)
(该语法来自 ksh)。