Shell 通配符和点文件

Shell 通配符和点文件

为什么下面两段代码能按预期工作:

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]*.

相关内容