Bash中shift命令为何会干扰已创建的关联数组?
问题:shift命令为何干扰已创建的关联数组?
我编写了一个简单脚本,用于匹配以短横线开头的位置参数并将其存入关联数组,代码如下:
declare -A opts for i; do [[ "$i" =~ - ]] && opts[$i]=1 done shift "${#opts[*]}" echo "opts: ${opts[*]}" echo "!opts: ${!opts[-d]}" echo "Query: $*"
执行./script -d hello world时,输出为:
opts: 1 !opts: hello Query: hello world
这不符合预期——如果-d已定义,${!opts[-d]}应该返回键-d本身。移除shift命令后,输出恢复正常:
opts: 1 !opts: -d Query: -d hello world
请问为何shift命令会干扰已创建的关联数组?
原因分析
问题的核心是你误解了${!opts[-d]}的语法含义,shift只是间接触发了这个语法的歧义表现:
${!opts[-d]}的实际行为:
在bash中,${!var}是间接引用语法,作用是“获取变量名为$var的变量的值”。当你写${!opts[-d]}时,bash会先计算opts[-d]的值(这里是1,因为你给opts[-d]赋值为1),然后${!1}会被解析为“获取第1个位置参数的值”,而非“获取关联数组opts中键为-d的键名”。shift的影响:
- 执行
shift "${#opts[*]}"时,${#opts[*]}的值是1(关联数组仅包含一个键-d),因此shift会移除第一个位置参数-d,此时$1变为hello。 - 这时候
${!1}就返回hello,也就是你看到的异常输出。 - 移除shift后,
$1仍是-d,所以${!1}返回-d,看起来符合预期,但这只是巧合,并非正确的关联数组键名获取方式。
- 执行
正确的关联数组键操作方式:
- 若要检查
-d是否为关联数组的键并输出它,可使用:[[ -v opts[-d] ]] && echo "-d" - 若要获取关联数组的所有键,可使用
${!opts[@]}。
- 若要检查
内容的提问来源于stack exchange,提问作者formigoni
相关产品推荐
相关产品推荐

