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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4069188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:49:36  来源:igfitidea点击:

How to pass an associative array as argument to a function in Bash?

arraysbashassociative-arrayassociative

提问by niksfirefly

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[@]"

回答by Florian Feldhaus

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 entry to associative arrays,其中详细解释了它们。最后一部分给了我以下对我有用的想法:

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

回答by ling

Based on Florian Feldhaus's solution:

基于 Florian Feldhaus 的解决方案:

# Bash 4+ only
function printAssocArray # ( assocArrayName ) 
{
    var=$(declare -p "")
    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

回答by Todd Lehman

If you're using Bash 4.3 or newer, the cleanestway is to pass the associative array by name and then access it inside your function using a name reference with local -n. For example:

如果您使用的是 Bash 4.3 或更新版本,最简洁的方法是按名称传递关联数组,然后使用带有local -n. 例如:

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

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

You don't have to use the _refsuffix; that's just what I picked here. You can call the reference anything you want so long as it's different from the original variable name (otherwise youll get a "circular name reference" error).

您不必使用_ref后缀;这正是我在这里挑选的。只要它与原始变量名称不同,您就可以调用任何您想要的引用(否则您将收到“循环名称引用”错误)。

回答by Orwellophile

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  )"; eval "declare -A E=${e#*=}"'
alias array.foreach='array.keys ; 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  )"
    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" )'

回答by aks

You can only pass associative arrays by name.

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

It's better (more efficient) to pass regular arrays by name also.

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

回答by Nickotine

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[]} 

eZ

eZ

回答by Samuel Powell

Here is a solution I came up with today using eval echo ...to do the indirection:

这是我今天提出的eval echo ...用于进行间接寻址的解决方案:

print_assoc_array() {
    local arr_keys="${![@]}" # $ means we only substitute the 
    local arr_val="${[\"$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

回答by l0b0

From the best Bash guideever:

来自有史以来最好的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 notan 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."

我觉得你的情况的问题是,$@不是关联数组:“@:扩展到所有的位置参数的所有的话。如果双引号括起来,它扩展到所有的位置参数作为单个单词的列表。”