设置 nullglob 时不会取消关联数组

Dan*_*n R 3 bash quotes associative-array glob shopt

当我在 bash 中设置 nullglob 时:

shopt -s nullglob
Run Code Online (Sandbox Code Playgroud)

然后声明一个关联数组:

declare -A arr=( [x]=y )
Run Code Online (Sandbox Code Playgroud)

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

unset arr[x]
echo ${#arr[@]} # still 1
Run Code Online (Sandbox Code Playgroud)

但是,取消设置nullglob使此操作像我期望的那样工作:

shopt -u nullglob
unset arr[x]
echo ${#arr[@]} # now it's 0; x has been removed
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?我不明白 shell globbing 如何与这种情况相关。我已经在 bash 4.4.19 和 5.0.0 上测试过了。

pax*_*blo 5

这可以通过参考bash文档(man页面)来解释,解释如下:

词的拆分之后,除非该-f选项已被设置,猛砸扫描每个字的人物'*''?''['。如果出现这些字符中的一个,则该单词被视为一个模式,并替换为按字母顺序排序的与该模式匹配的文件名列表。

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

换句话说,nullglob影响你的arr[x]论点会发生什么。它要么被单独留下,要么被移除。

您可以通过使用以下命令打开 echo-before-execute 标志来查看此效果set -x

pax$ declare -A arr=( [x]=y )
pax$ shopt -s nullglob
pax$ set -x
pax$ unset arr[x]
+ unset
Run Code Online (Sandbox Code Playgroud)

请注意,这是“单词被删除”的情况。“单词保持不变”的情况如下所示:

pax$ shopt -u nullglob
+ shopt -u nullglob
pax$ unset arr[x]
+ unset 'arr[x]'
Run Code Online (Sandbox Code Playgroud)

上面最后的回显命令还提供了有关如何删除条目的线索,如果您启用了nullglob. 只需引用防止扩展的参数:

unset 'arr[x]'
Run Code Online (Sandbox Code Playgroud)

无论nullglob设置如何,这都将起作用,因为文档中有关引用的部分:

将字符括在单引号中会保留引号内每个字符的字面值。