为什么下面两段代码能按预期工作:
ls -d .[!.]?*
echo [D]*
但以下 2 个则不然:
ls -d [.][!.]?*
echo [D]
在第一个命令中,我收到错误:
ls: cannot access [.][!.]*: No such file or directory
当我试图获得相同的列表时ls -d .[!.]?*
。对于第二个,输出是:
[D]
当我期待类似 的错误声明时No such file or directory
。我缺少什么?如果上面第二组示例中显示的通配符元素不能消除表达式,那么究竟是什么使表达式成为通配符?
澄清(也在评论中):
通配符[D]*
不仅输出D
,它还输出Desktop
, Downloads
... 等等。但是,echo [D]
当我有一个名为 D 的文件时和没有时,我也尝试过。当文件存在时输出有效,但当文件不存在时D
我也得到输出。[D]
我不明白为什么。为什么目录中文件的存在将表达式 [D] 从通配符更改为非通配符?
答案1
默认情况下,bash(shell)不会扩展以点开头的文件名(被视为隐藏文件),除非显式指定点。由于[.]
是一种模式,而不是文字字符,因此它不会触发隐藏文件的显示,因此ls -d [.][!.]?*
不匹配任何内容。
您可以通过运行来更改此默认行为shopt -s dotglob
,这会将选项设置为在扩展文件名模式(称为“通配”)时始终包含隐藏文件。
示例(行首的美元符号表示 shell 提示符;请勿输入):
$ touch .foo
$ ls -d .[!.]?*
.foo
$ ls -d [.][!.]?*
ls: cannot access [.][!.]?*: No such file or directory
$ shopt -s dotglob
$ ls -d [.][!.]?*
.foo
问题echo [D]
是如果没有文件名匹配,则不会发生扩展。由于您D
在尝试时没有指定文件,echo
因此给出并回显了您实际输入的内容。
仅当文件名匹配时才会发生路径名扩展的示例:
$ touch apple
$ echo a*
apple
$ rm apple
$ echo a*
a*
如果您删除所有匹配的文件[D]*
,则echo [D]*
会给您[D]*
.