如何将关联数组作为参数传递给Bash中的函数?

时间:2010-11-01 13:16:54

标签: arrays bash associative-array associative

如何将关联数组作为参数传递给函数?在Bash中这可能吗?

以下代码未按预期运行:

function iterateArray
{
    local ADATA="${@}"            # associative array

for key in "${!ADATA[@]}"
do
    echo "key - ${key}"
    echo "value: ${ADATA[$key]}"

done

}

将关联数组传递给类似普通数组的函数不起作用:

iterateArray "$A_DATA"

iterateArray "$A_DATA[@]"

8 个答案:

答案 0 :(得分:37)

上周我遇到了完全相同的问题并且考虑了很长一段时间。

似乎无法对关联数组进行序列化或复制。对explains them in detail的关联数组有一个很好的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)" 

答案 1 :(得分:10)

基于 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" 

输出将是:

doo: 456
pou: 789
mail: ab\npo

答案 2 :(得分:6)

更新,完全回答这个问题,这是我图书馆的一小部分:

通过引用

迭代关联数组
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

这是我早期工作的开端,我将在下面留下。

@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" )'

答案 3 :(得分:4)

您只能按名称传递关联数组。

按名称传递常规数组会更好(更有效)。

答案 4 :(得分:2)

哟:

 #!/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

答案 5 :(得分:1)

这是我今天使用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

bash 4.3上的输出:

def: 456
abc: 123

答案 6 :(得分:1)

如果您使用的是Bash 4.3或更高版本,则 cleanest 的方法是按名称传递关联数组,然后使用带有local -n的名称引用在函数内部访问它。例如:

function foo {
    local -n data_ref=$1
    echo ${data_ref[a]} ${data_ref[b]}
}

declare -A data
data[a]="Fred Flintstone"
data[b]="Barney Rubble"
foo data

您不必使用_ref后缀;这就是我在这里选择的只要它与原始变量名不同,就可以调用引用的任何内容(否则会出现“循环名称引用”错误)。

答案 7 :(得分:0)

来自最好的Bash guide

declare -A fullNames
fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
for user in "${!fullNames[@]}"
do
    echo "User: $user, full name: ${fullNames[$user]}."
done

我认为你的案例中的问题是$@ is not an associative array:“@:扩展到所有位置参数的所有单词。如果双引号,它会扩展为所有位置参数的列表,作为单个单词。 “