How do you pass an associative array as an argument to a function? Is this possible in Bash?
如何将关联数组作为参数传递给函数?这在Bash中可能吗?
The code below is not working as expected:
下面的代码没有按预期工作:
function iterateArray
{
local ADATA="${@}" # associative array
for key in "${!ADATA[@]}"
do
echo "key - ${key}"
echo "value: ${ADATA[$key]}"
done
}
Passing associative arrays to a function like normal arrays does not work:
将关联数组传递给像普通数组这样的函数是行不通的:
iterateArray "$A_DATA"
or
或
iterateArray "$A_DATA[@]"
7 个解决方案
#1
34
I had exactly the same problem last week and thought about it for quite a while.
上周我遇到了同样的问题,想了很久。
It seems, that associative arrays can't be serialized or copied. There's a good Bash FAQ entry to associative arrays which explains them in detail. The last section gave me the following idea which works for me:
似乎关联数组不能序列化或复制。有一个很好的关于关联数组的Bash FAQ条目,它详细地解释了它们。最后一部分给了我以下对我有用的想法:
function print_array {
# eval string into a new associative array
eval "declare -A func_assoc_array="${1#*=}
# proof that array was successfully created
declare -p func_assoc_array
}
# declare an associative array
declare -A assoc_array=(["key1"]="value1" ["key2"]="value2")
# show associative array definition
declare -p assoc_array
# pass associative array in string form to function
print_array "$(declare -p assoc_array)"
#2
8
Based on Florian Feldhaus's solution:
根据Florian Feldhaus的解决方案:
# Bash 4+ only
function printAssocArray # ( assocArrayName )
{
var=$(declare -p "$1")
eval "declare -A _arr="${var#*=}
for k in "${!_arr[@]}"; do
echo "$k: ${_arr[$k]}"
done
}
declare -A conf
conf[pou]=789
conf[mail]="ab\npo"
conf[doo]=456
printAssocArray "conf"
The output will be:
的输出将会是:
doo: 456
pou: 789
mail: ab\npo
#3
6
Update, to fully answer the question, here is an small section from my library:
更新,充分回答这个问题,以下是我的图书馆的一小部分:
Iterating an associative array by reference
shopt -s expand_aliases
alias array.getbyref='e="$( declare -p ${1} )"; eval "declare -A E=${e#*=}"'
alias array.foreach='array.keys ${1}; for key in "${KEYS[@]}"'
function array.print {
array.getbyref
array.foreach
do
echo "$key: ${E[$key]}"
done
}
function array.keys {
array.getbyref
KEYS=(${!E[@]})
}
# Example usage:
declare -A A=([one]=1 [two]=2 [three]=3)
array.print A
This we a devlopment of my earlier work, which I will leave below.
这是对我早期作品的总结,我将在下面留下。
@ffeldhaus - nice response, I took it and ran with it:
@ffeldhaus -回复不错,我拿着它跑了:
t()
{
e="$( declare -p $1 )"
eval "declare -A E=${e#*=}"
declare -p E
}
declare -A A='([a]="1" [b]="2" [c]="3" )'
echo -n original declaration:; declare -p A
echo -n running function tst:
t A
# Output:
# original declaration:declare -A A='([a]="1" [b]="2" [c]="3" )'
# running function tst:declare -A E='([a]="1" [b]="2" [c]="3" )'
#4
3
You can only pass associative arrays by name.
只能通过名称传递关联数组。
It's better (more efficient) to pass regular arrays by name also.
通过名称传递常规数组更好(更有效)。
#5
2
yo:
哟:
#!/bin/bash
declare -A dict
dict=(
[ke]="va"
[ys]="lu"
[ye]="es"
)
fun() {
for i in $@; do
echo $i
done
}
fun ${dict[@]} # || ${dict[key]} || ${!dict[@] || ${dict[$1]}
eZ
易之
#6
1
Here is a solution I came up with today using eval echo ...
to do the indirection:
下面是我今天使用eval echo提出的解决方案。间接的:
print_assoc_array() {
local arr_keys="\${!$1[@]}" # \$ means we only substitute the $1
local arr_val="\${$1[\"\$k\"]}"
for k in $(eval echo $arr_keys); do #use eval echo to do the next substitution
printf "%s: %s\n" "$k" "$(eval echo $arr_val)"
done
}
declare -A my_arr
my_arr[abc]="123"
my_arr[def]="456"
print_assoc_array my_arr
Outputs on bash 4.3:
在bash 4.3输出:
def: 456
abc: 123
#7
0
From the best Bash guide ever:
来自有史以来最好的Bash指南:
declare -A fullNames
fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
for user in "${!fullNames[@]}"
do
echo "User: $user, full name: ${fullNames[$user]}."
done
I think the issue in your case is that $@
is not an associative array: "@: Expands to all the words of all the positional parameters. If double quoted, it expands to a list of all the positional parameters as individual words."
我认为您的问题是$@不是一个关联数组:“@:扩展到所有位置参数的所有单词。如果双引号,它将扩展为所有位置参数作为单个单词的列表。
#1
34
I had exactly the same problem last week and thought about it for quite a while.
上周我遇到了同样的问题,想了很久。
It seems, that associative arrays can't be serialized or copied. There's a good Bash FAQ entry to associative arrays which explains them in detail. The last section gave me the following idea which works for me:
似乎关联数组不能序列化或复制。有一个很好的关于关联数组的Bash FAQ条目,它详细地解释了它们。最后一部分给了我以下对我有用的想法:
function print_array {
# eval string into a new associative array
eval "declare -A func_assoc_array="${1#*=}
# proof that array was successfully created
declare -p func_assoc_array
}
# declare an associative array
declare -A assoc_array=(["key1"]="value1" ["key2"]="value2")
# show associative array definition
declare -p assoc_array
# pass associative array in string form to function
print_array "$(declare -p assoc_array)"
#2
8
Based on Florian Feldhaus's solution:
根据Florian Feldhaus的解决方案:
# Bash 4+ only
function printAssocArray # ( assocArrayName )
{
var=$(declare -p "$1")
eval "declare -A _arr="${var#*=}
for k in "${!_arr[@]}"; do
echo "$k: ${_arr[$k]}"
done
}
declare -A conf
conf[pou]=789
conf[mail]="ab\npo"
conf[doo]=456
printAssocArray "conf"
The output will be:
的输出将会是:
doo: 456
pou: 789
mail: ab\npo
#3
6
Update, to fully answer the question, here is an small section from my library:
更新,充分回答这个问题,以下是我的图书馆的一小部分:
Iterating an associative array by reference
shopt -s expand_aliases
alias array.getbyref='e="$( declare -p ${1} )"; eval "declare -A E=${e#*=}"'
alias array.foreach='array.keys ${1}; for key in "${KEYS[@]}"'
function array.print {
array.getbyref
array.foreach
do
echo "$key: ${E[$key]}"
done
}
function array.keys {
array.getbyref
KEYS=(${!E[@]})
}
# Example usage:
declare -A A=([one]=1 [two]=2 [three]=3)
array.print A
This we a devlopment of my earlier work, which I will leave below.
这是对我早期作品的总结,我将在下面留下。
@ffeldhaus - nice response, I took it and ran with it:
@ffeldhaus -回复不错,我拿着它跑了:
t()
{
e="$( declare -p $1 )"
eval "declare -A E=${e#*=}"
declare -p E
}
declare -A A='([a]="1" [b]="2" [c]="3" )'
echo -n original declaration:; declare -p A
echo -n running function tst:
t A
# Output:
# original declaration:declare -A A='([a]="1" [b]="2" [c]="3" )'
# running function tst:declare -A E='([a]="1" [b]="2" [c]="3" )'
#4
3
You can only pass associative arrays by name.
只能通过名称传递关联数组。
It's better (more efficient) to pass regular arrays by name also.
通过名称传递常规数组更好(更有效)。
#5
2
yo:
哟:
#!/bin/bash
declare -A dict
dict=(
[ke]="va"
[ys]="lu"
[ye]="es"
)
fun() {
for i in $@; do
echo $i
done
}
fun ${dict[@]} # || ${dict[key]} || ${!dict[@] || ${dict[$1]}
eZ
易之
#6
1
Here is a solution I came up with today using eval echo ...
to do the indirection:
下面是我今天使用eval echo提出的解决方案。间接的:
print_assoc_array() {
local arr_keys="\${!$1[@]}" # \$ means we only substitute the $1
local arr_val="\${$1[\"\$k\"]}"
for k in $(eval echo $arr_keys); do #use eval echo to do the next substitution
printf "%s: %s\n" "$k" "$(eval echo $arr_val)"
done
}
declare -A my_arr
my_arr[abc]="123"
my_arr[def]="456"
print_assoc_array my_arr
Outputs on bash 4.3:
在bash 4.3输出:
def: 456
abc: 123
#7
0
From the best Bash guide ever:
来自有史以来最好的Bash指南:
declare -A fullNames
fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
for user in "${!fullNames[@]}"
do
echo "User: $user, full name: ${fullNames[$user]}."
done
I think the issue in your case is that $@
is not an associative array: "@: Expands to all the words of all the positional parameters. If double quoted, it expands to a list of all the positional parameters as individual words."
我认为您的问题是$@不是一个关联数组:“@:扩展到所有位置参数的所有单词。如果双引号,它将扩展为所有位置参数作为单个单词的列表。