I'm trying to manage a list of associative arrays with an array in bash, and I can't seem to pick up what's not going right.
我正在尝试用bash中的数组管理一个关联数组列表,我似乎无法找到不正确的东西。
What I'm trying to do:
我想做什么:
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
That all seems to work fine as I can manually return values by referencing ${a[key]}
just fine.
这一切似乎工作正常,因为我可以通过引用$ {a [key]}手动返回值。
However, when I'm trying to iterate through using the array
variable it's not really giving me what I expect.
但是,当我试图迭代使用数组变量时,它并没有真正给我我所期望的。
for index in ${array[@]}; do
echo ${index[key]}
done
Is returning the same as if I were to run
回来就好像我要跑
for index in ${array[@]}; do
echo $index
done
I feel like I'm missing something simple, but searching for an answer isn't turning up any solutions. Any assistance would be appreciated.
我觉得我错过了一些简单的东西,但寻找答案并没有找到任何解决方案。任何援助将不胜感激。
1 个解决方案
#1
7
Here's one solution, using shell indirection. This will work with any bash
which supports associative arrays. The indirection must contain the entire reference, including subscripts, which is a bit awkward.
这是一个使用shell间接的解决方案。这适用于任何支持关联数组的bash。间接必须包含整个引用,包括下标,这有点尴尬。
for index in "${array[@]}"; do
indexkey=${index}[key]
echo "${!indexkey}"
done
With a modern bash
(at least v4.3), you can use nameref declarations, which create aliases. This is a lot more convenient, because you can use different keys with the same alias:
使用现代bash(至少v4.3),您可以使用nameref声明来创建别名。这样更方便,因为您可以使用具有相同别名的不同键:
for index in "${array[@]}"; do
declare -n subarray=$index
echo "${subarray[key]}"
done
Something approaching an explanation.
As Etan Reisner points out in a comment, this question is dealt with at some length in a Bash FAQ entry. However, on the date that I write, that FAQ entry includes the disclaimer "Overhauling this page will take some time and work", and it is certainly true that the FAQ entry is not currently as clear as one might like. So here's my brief summary:
正如Etan Reisner在评论中指出的那样,这个问题在Bash FAQ条目中有一定篇幅。但是,在我写的那天,该FAQ条目包括免责声明“检修此页面需要一些时间和工作”,而且FAQ条目目前还不像人们所希望的那样清晰。所以这是我的简短摘要:
-
declare
(and other related builtins, includingexport
,local
, andtypeset
) evaluate their arguments. So you can build up a variable name in adeclare
statement.declare(和其他相关的内置函数,包括export,local和typeset)评估它们的参数。因此,您可以在declare语句中构建变量名称。
-
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.由于declare也可以用于赋值(只要你使用相同的声明),你可以在declare语句中建立一个索引变量名。
-
If you are using bash4.3 or better, you can use namerefs (
typeset -n
ordeclare -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.如果您使用的是bash4.3或更高版本,则可以使用namerefs(typeset -n或declare -n)来模拟数组值。这实际上是你可以从bash函数返回一个数组的唯一方法,但它仍然有点尴尬,因为它要求函数的调用者提供一个带有数组名称的参数;此外,它不是完全健壮的,因为名称将在函数的范围内使用,因此它可能被局部变量遮蔽。需要注意。
-
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).只要$ {place}没有值包含冒号(当然,您可以使用不同的字符而不是冒号),将会工作。
-
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
7
Here's one solution, using shell indirection. This will work with any bash
which supports associative arrays. The indirection must contain the entire reference, including subscripts, which is a bit awkward.
这是一个使用shell间接的解决方案。这适用于任何支持关联数组的bash。间接必须包含整个引用,包括下标,这有点尴尬。
for index in "${array[@]}"; do
indexkey=${index}[key]
echo "${!indexkey}"
done
With a modern bash
(at least v4.3), you can use nameref declarations, which create aliases. This is a lot more convenient, because you can use different keys with the same alias:
使用现代bash(至少v4.3),您可以使用nameref声明来创建别名。这样更方便,因为您可以使用具有相同别名的不同键:
for index in "${array[@]}"; do
declare -n subarray=$index
echo "${subarray[key]}"
done
Something approaching an explanation.
As Etan Reisner points out in a comment, this question is dealt with at some length in a Bash FAQ entry. However, on the date that I write, that FAQ entry includes the disclaimer "Overhauling this page will take some time and work", and it is certainly true that the FAQ entry is not currently as clear as one might like. So here's my brief summary:
正如Etan Reisner在评论中指出的那样,这个问题在Bash FAQ条目中有一定篇幅。但是,在我写的那天,该FAQ条目包括免责声明“检修此页面需要一些时间和工作”,而且FAQ条目目前还不像人们所希望的那样清晰。所以这是我的简短摘要:
-
declare
(and other related builtins, includingexport
,local
, andtypeset
) evaluate their arguments. So you can build up a variable name in adeclare
statement.declare(和其他相关的内置函数,包括export,local和typeset)评估它们的参数。因此,您可以在declare语句中构建变量名称。
-
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.由于declare也可以用于赋值(只要你使用相同的声明),你可以在declare语句中建立一个索引变量名。
-
If you are using bash4.3 or better, you can use namerefs (
typeset -n
ordeclare -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.如果您使用的是bash4.3或更高版本,则可以使用namerefs(typeset -n或declare -n)来模拟数组值。这实际上是你可以从bash函数返回一个数组的唯一方法,但它仍然有点尴尬,因为它要求函数的调用者提供一个带有数组名称的参数;此外,它不是完全健壮的,因为名称将在函数的范围内使用,因此它可能被局部变量遮蔽。需要注意。
-
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).只要$ {place}没有值包含冒号(当然,您可以使用不同的字符而不是冒号),将会工作。
-
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