How do you pass an associative array as an argument to a function? Is this possible in Bash?
The code below is not working as expected:
function iter
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
If you're using Bash 4.3 or newer, the cleanest way is to pass the associative array by name and then access it inside your function using a name reference with local -n
. For example:
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
You don't have to use the _ref
suffix; 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).
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:
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)"
Based on Florian Feldhaus's solution:
# 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
Here is a solution I came up with today using eval echo ...
to do the indirection:
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:
def: 456
abc: 123
You can only pass associative arrays by name.
It's better (more efficient) to pass regular arrays by name also.