在bash中获取变量名为数组的键

3

在我的bash脚本中,我有两个数组。根据一些逻辑,其中一个或另一个将被使用,因此我会用变量varName获取所需数组的名称。我可以确保使用以下代码获取该数组的值,但是否有方法获取其键?尝试了几个选项,但没有成功。

declare -A foo=([a]=b [c]=d)
declare -A bar=([e]=f [g]=h)

varName=foo
varArray=$varName[@]
echo ${!varArray}

感谢您。
2个回答

3

不幸的是,如果不使用eval,就无法实现。为了安全起见,请确保varName只是一个有效标识符。

[[ varName =~ ^[a-zA-Z_][a-zA-Z_0-9]+$ ]] && eval "echo \${!$varName[@]}"

eval是必要的,以便提供第二轮解析和评估。在第一轮中,Shell执行通常的参数扩展,结果是将字符串echo ${!foo[@]}作为单个参数传递给eval。(特别地,第一个美元符号被转义,因此被字面传递;$varName被扩展为foo;并且引号作为引号移除的一部分被删除。eval然后解析并评估字符串。

$ eval "echo \${!$varName[@]}"
#       echo  ${!foo     [@]}
#  The above is the argument that `eval` sees, after the shell
#  does the normal evaluation before calling `eval`. Parameter
#  expansion replaces $varName with foo and quote removal gets
#  rid of the backslash before `$` and the double quotes.
a c

如果您使用的是bash 4.3或更高版本,则可以使用nameref。
declare -n varName=foo
for key in "${!varName[@]}"; do
    echo "$key"
done

那么评估的结果将是一个字符串,对吧?这意味着它不能用于 for 循环,对吧?那么选项就是通过 IFS 传递它,或者还有更优雅的解决方案吗?再次感谢。 - user487772
是的,它将是一个单字符串,因此包含空格的键将会出现问题。我不确定在 bash 4.2 或更早版本中是否能想到更好的解决方案。我刚刚想起来,在 bash 4.3 中可以使用 nameref,如果可以的话。 - chepner
太棒了!非常感谢! - user487772

0

有一种安全的IFS方法可以间接地获取数组的键(或值):

declare -a things=("an apple" "a banana")
declare -a tmp
arrayName=things
eval "tmp=(\"\${$arrayName[@]}\")"
# "${tmp[@]}" is now ("an apple" "a banana")

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