为什么 shopt -s nullglob 删除数组元素中带有问号的字符串?

为什么 shopt -s nullglob 删除数组元素中带有问号的字符串?

这个小设定让我抓狂:

shopt -s nullglob

我在 bash 4.3 脚本中使用它作为全局设置避免扫描空目录时出错

现在我发现了一个我不明白的奇怪问题:

# shopt -s nullglob
# array=(foo bar)
# echo "${array[@]}"
foo bar
# array=(foo bar?)
# echo "${array[@]}"
foo
# shopt -u nullglob
# array=(foo bar)
# echo "${array[@]}"
foo bar
# array=(foo bar?)
# echo "${array[@]}"
foo bar?

正如您所看到的,它bar?从数组元素中删除了 ,但为什么呢?这文档指的是可以包含*和 的文件名模式?,但单独的数组与“不匹配文件”无关:

If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves.

这是一个错误吗?

PS 我将在循环周围设置/取消设置 nullglob 来解决我的问题。这不是问题!

更新1

正如@MichaelHomer 所要求的:

# shopt -s nullglob
# array=(*)
# echo "${array[@]}"
1 Video_folder Server bin config dev etc etc.defaults initrd lib lib32 lib64 lost+found mnt proc root run sbin storage sys tmp tmpRoot usr var var.defaults volume1
# shopt -u nullglob
# array=(*)
# echo "${array[@]}"
1 Video_folder Server bin config dev etc etc.defaults initrd lib lib32 lib64 lost+found mnt proc root run sbin storage sys tmp tmpRoot usr var var.defaults volume1

这意味着?

答案1

当您这样做时array=(foo bar?),该bar?字符串不带引号,并且包含文件名通配字符?(与任何单个字符匹配)。这意味着 shell 将对此值执行文件名通配。如果模式不匹配任何内容,则默认情况下保持原样。如果它匹配某些内容(例如bar1、等),bar-bar.匹配的名称将被插入到数组中。

启用后,如果没有文件名与其匹配,nullglob则不带引号的通配模式将被完全删除(这通常是人们想要启用的原因)。这意味着在这种情况下,您的数组将仅包含该元素。bar?nullglobfoo

换句话说,该设置将(除非您在当前目录中nullglob调用了一个文件)甚至阻止将未加引号的单词指定为数组中的元素。bar?bar?

如果您想要两个字符串foobar?在数组中,补救措施是引用它们(foo不需要引用,但保持一致不会有什么坏处):

array=('foo' 'bar?')

“解决”这个问题的另一种方法是禁用文件名通配。这是通过以下方式完成的set -f

set -f
array=(foo bar?)
set +f

Michael 可能想展示的array=(*)是,未加引号的值(此处为未加引号的*)会发生通配。他想展示这一点,因为这是问题的根源。

相关内容