尝试增加关联数组元素时出现错误的数组下标错误

Bob*_*obi 7 bash associative-array

我可以创建一个关联数组并将一个整数分配给一个包含单引号的键:

$ declare -A dict
$ var="john's"
$ dict[$var]=1
$ echo ${dict[$var]}
1
$ declare -p dict
declare -A dict=(["john's"]="1" )
Run Code Online (Sandbox Code Playgroud)

但是当我尝试增加它的价值时:

$ (( dict[$var]++ ))
bash: ((: dict[john's]++ : bad array subscript (error token is "dict[john's]++ ")
$ (( dict["$var"]++ ))
bash: ((: dict[john's]++ : bad array subscript (error token is "dict[john's]++ ")
$ (( dict["${var}"]++ ))
bash: ((: dict[john's]++ : bad array subscript (error token is "dict[john's]++ ")
Run Code Online (Sandbox Code Playgroud)

我总是得到同样的错误。我究竟做错了什么?

Ini*_*ian 7

keyname 中的单引号导致解析器将其视为未终止的引号字符。解决此问题的一种方法是转义'键中的字符

key="john's"
printf -v escKey "%q" "$key"
Run Code Online (Sandbox Code Playgroud)

现在由于说明%q符,printf()将对所有 shell 元字符应用所需的转义,即使其“shell-quoted”和可重用。如果您打印内容,escKey您会注意到'转义

printf '%s\n' "$escKey"
john\'s
Run Code Online (Sandbox Code Playgroud)

现在您可以在关联数组中使用此键名。请记住,您始终可以手动添加可能会很乱的转义符。由于%q是 shell 提供的本机方式,因此使用它非常安全。

(( dict["$escKey"]++ ))
Run Code Online (Sandbox Code Playgroud)

同样在bash版本 >= 4.4参数扩展具有@Q这是您可以使用的%q说明符的快捷方式printf()

(( dict["${key@Q}"]++ ))
Run Code Online (Sandbox Code Playgroud)

  • 如果使用“declare -iA dict”将整数标志添加到关联数组,则可以使用“dict[$var]+=1”增加条目,而无需引用/转义键。仅在算术表达式中才需要转义键。很高兴知道这个怪癖。 (4认同)

ogu*_*ail 6

您需要确保,通过转义$,那$var才会展开猛砸开始分析dict[$var]++算术表达式。

$ (( dict[\$var]++ ))
$ declare -p dict
declare -A dict=(["john's"]="2" )
Run Code Online (Sandbox Code Playgroud)

在较新版本的 Bash 上,启用assoc_expand_onceshell 选项也有效,但是当从不受信任的来源读取密钥时,这是不安全的Stephane 的回答中$var给出了一个示例,说明即使启用此选项,shell 仍然可以被诱骗执行带有污染的任意命令。