当设置了nullglob时,关联数组未被取消设置

3

当我在bash中设置nullglob时:

shopt -s nullglob

然后声明一个关联数组:

declare -A arr=( [x]=y )

我无法取消数组中的特定键:

unset arr[x]
echo ${#arr[@]} # still 1

然而,取消设置 nullglob 可以使得此操作按照我的期望方式工作:
shopt -u nullglob
unset arr[x]
echo ${#arr[@]} # now it's 0; x has been removed

这里发生了什么?我不明白shell通配符如何与此相关。我已在bash 4.4.19和5.0.0上进行了测试。

1
这与nullglob和数组非常相似。 - Inian
请查看 echo unset arr[x] - Cyrus
1个回答

5

这可以通过参考 bash 文档(即 man 页面)来解释,以下是其概括:

在单词分割之后,除非设置了 -f 选项,否则 Bash 会扫描每个单词中的字符 '*''?''['。如果发现其中一个字符,则将该单词视为模式,并用与模式匹配的按字母顺序排序的文件名列表替换之。

如果没有找到匹配的文件名且 shell 选项 nullglob 被禁用,则保留该单词不变。如果设置了 nullglob 选项但未找到匹配项,则删除该单词。

换句话说,nullglob 会影响你的 arr[x] 参数的处理方式。它可能被保留或被删除。

你可以通过打开执行前显示命令标志 set -x 来查看此效果:

pax$ declare -A arr=( [x]=y )
pax$ shopt -s nullglob
pax$ set -x
pax$ unset arr[x]
+ unset

请注意,这是“删除单词”的情况。而“保留单词不变”的情况如下所示:
pax$ shopt -u nullglob
+ shopt -u nullglob
pax$ unset arr[x]
+ unset 'arr[x]'

上述最后一个回显的命令也提示了如果您启用了nullglob,如何删除条目。只需引用参数以防止扩展:
unset 'arr[x]'

无论 nullglob 的设置如何,这都能正常工作,因为文档中引用的引号部分说明了单引号可以保留其中每个字符的字面值。

谢谢!如果没有 Stack Overflow,我就无法编写 Bash 脚本了。我会花费数小时来尝试解决这个问题。有人对 nullglob 默认开启还是关闭有意见吗? - Christopher King
仅供参考,此怪异现象的数组不必是关联的。比较shopt -u nullglob; a=(unset_me); unset a[0]; echo "${a[@]}"shopt -s nullglob; a=(unset_me); unset a[0]; echo "${a[@]}"; 完全相同。 - Andrej Podzimek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接