在bash中的关联数组名称的数组

5

我正在尝试使用bash中的数组来管理关联数组列表,但似乎无法确定出问题的原因。

我想要做的事情:

array=(a b c d)

for i in ${array[@]}; do
    declare -A $i
done

a[key]=avalue
b[key]=bvalue
c[key]=cvalue
d[key]=dvalue

看起来这一切都很好,因为我可以通过引用${a[key]}手动返回值。

然而,当我尝试使用array变量进行迭代时,它并没有给我我期望的结果。

for index in ${array[@]}; do
  echo ${index[key]}
done

返回是否等同于我运行

for index in ${array[@]}; do
  echo $index
done

我感觉自己缺少一些简单的东西,但是搜索答案并没有找到任何解决方案。如果能得到帮助将不胜感激。


2
这里可能会有所帮助:http://mywiki.wooledge.org/BashFAQ/006。 - Etan Reisner
1个回答

8

这里有一个解决方案,使用shell间接引用。这个方法适用于任何支持关联数组的bash版本。间接引用必须包含整个引用,包括下标,这有点麻烦。

for index in "${array[@]}"; do
  indexkey=${index}[key]
  echo "${!indexkey}"
done

使用现代的bash(至少是v4.3),您可以使用命名引用声明,它会创建别名。这更加方便,因为您可以使用相同的别名和不同的键:

for index in "${array[@]}"; do
  declare -n subarray=$index
  echo "${subarray[key]}"
done

一些解释

正如Etan Reisner在评论中指出的那样,这个问题在Bash FAQ entry中得到了详细解答。然而,在我写这篇文章的时候,该FAQ条目包括免责声明“彻底修订此页面需要一些时间和工作”,并且可以肯定的是,该FAQ条目目前并不像人们希望的那样清晰明了。因此,以下是我的简要总结:

  1. declare (and other related builtins, including export, local, and typeset) evaluate their arguments. So you can build up a variable name in a declare statement.

  2. Since declare can also be used to assign values (as long as you use the same declaration), you can build up an index variable name in a declare statement.

  3. If you are using bash4.3 or better, you can use namerefs (typeset -n or declare -n) in order to simulate array values. That's really the only way you can return an array from a bash function, but it is still a bit awkward since it requires the caller of the function to provide an argument with the name of the array; furthermore, it is not entirely robust since the name will be used in the scope of the function so it might be shadowed by a local variable. Caution is required.

  4. There is probably no other good reason to use variable indirection. If you find yourself needing it, think about whether you could structure your program differently. You can collapse associative keys with string concatenation. For example:

    my_array[${place}:${feature}]
    

    will work find as long as no value for ${place} contains a colon (of course, you could use a different character instead of colon).

  5. Watch out with keys. If an array is declared associative, the key is evaluated more or less normally, but if it is a normal indexed array, the key is evaluated as an arithmetic expression. The consequence is that

    declare -A assoc
    declare -a indexed
    key=42
    # This assigns the element whose key is "key"
    assoc[key]=foo
    # This assigns the element whose key is 42
    indexed[key]=foo
    # If $key had not been defined, the above would have assigned
    # the element whose key was 0, without an error message
    

1
@gniourf_gniourf:谢谢。 - rici
我希望找到一种避免使用 eval 的方法,看来你给了我一个。非常感谢! - Mycah

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