4

What's the best way to pass an associative array as an argument to a function to avoid the repetition of having to iterate over numerous associate arrays? That way I can give the function any array of my choice to print. Here's what I have:

# Snippet

declare -A weapons=(
  ['Straight Sword']=75
  ['Tainted Dagger']=54
  ['Imperial Sword']=90
  ['Edged Shuriken']=25
)

print_weapons() {
  for i in "${!weapons[@]}"; do
    printf "%s\t%d\n" "$i" "${weapons[$i]}"
  done
}

print_weapons
theGrayFox
  • 921
  • 1
  • 10
  • 22
  • 1
    Did you have a look at http://stackoverflow.com/questions/4069188/how-to-pass-an-associative-array-as-argument-to-a-function-in-bash/8879444#8879444 ? – Florian Feldhaus Aug 08 '13 at 18:33

4 Answers4

19

you can use local -n for a reference

 declare -A weapons=(
 ['Straight Sword']=75
 ['Tainted Dagger']=54
 ['Imperial Sword']=90
 ['Edged Shuriken']=25
 )
 
 print_weapons() {
     local -n array=$1
     for i in "${!array[@]}"; do
         printf "%s\t%d\n" "$i" "${array[$i]}"
     done
 }
 
 print_weapons weapons
mug896
  • 1,777
  • 1
  • 19
  • 17
  • local -n option does not work on GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu): `local: -n: invalid option` – Drew May 27 '17 at 19:10
  • 1
    @Drew: it was added in 4.3; see http://tiswww.case.edu/php/chet/bash/NEWS (it doesn't list `local` explicitly, but `local` handles the same types as `declare`) 4.3 was released in 2014-02, though distros don't pick it up new releases immediately – dave_thompson_085 Sep 07 '17 at 01:04
  • `local -n` - It's magic. – vskubriev Oct 15 '19 at 15:32
8

I don't think you can pass associative arrays as an argument to a function. You can use the following hack to get around the problem though:

#!/bin/bash

declare -A weapons=(
  ['Straight Sword']=75
  ['Tainted Dagger']=54
  ['Imperial Sword']=90
  ['Edged Shuriken']=25
)

function print_array {
    eval "declare -A arg_array="${1#*=}
    for i in "${!arg_array[@]}"; do
       printf "%s\t%s\n" "$i ==> ${arg_array[$i]}"
    done
}

print_array "$(declare -p weapons)" 

Output

Imperial Sword ==> 90   
Tainted Dagger ==> 54   
Edged Shuriken ==> 25   
Straight Sword ==> 75   
jaypal singh
  • 74,723
  • 23
  • 102
  • 147
  • This is what I was looking at through an article, and this may just be the best bet. I really appreciate the help! – theGrayFox Jul 09 '13 at 20:56
  • Looks like this was copied (and then slightly edited) from https://stackoverflow.com/a/8879444/813602; please note that extending the double quotes around the `${1#*=}` fixes whitespace issues (as commented in the original answer). – Ingo Karkat Apr 28 '21 at 18:30
2

It's ugly enough using variable indirection with regular arrays, working with associative arrays is difficult -- I did not find a way to iterate over the keys.

I wonder if all you need is declare -p:

print_array() { declare -p $1; }
print_array weapons
declare -A weapons='(["Imperial Sword"]="90" ["Tainted Dagger"]="54" ["Edged Shuriken"]="25" ["Straight Sword"]="75" )'

Or, prettier:

print_array() { declare -p $1 | sed 's/[[)]/\n&/g'; }
print_array weapons
declare -A weapons='(
["Imperial Sword"]="90" 
["Tainted Dagger"]="54" 
["Edged Shuriken"]="25" 
["Straight Sword"]="75" 
)'
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0
#!/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]} || ${dict[@]}
Nickotine
  • 167
  • 6
  • 1
    This does not pass the array keys to the function. – Armali Sep 07 '17 at 07:39
  • 1
    ... here are your options you can pass in a key with no issues: I add a comment – Nickotine Sep 08 '17 at 22:45
  • The samples work for me. i.e. `fun ${dict[ke]}` produces output `va`. I suppose if you want to use it as `fun ke`, then you have to communicate the name of the array to the function somehow OR use a "well-defined" array name that can be hard-coded (but that's ugly, I guess). Good luck to all. – shellter Sep 25 '20 at 13:38
  • What do you mean? @shellter – Nickotine Sep 26 '20 at 14:18
  • I’d you want to pass in the keys then do `${!dict[@]}` – Nickotine Sep 26 '20 at 14:28
  • 1
    I'm agreeing with your post ;-? ... But I'm adding the comment that some users might be lazy and expect to pass just the key text, i.e. `fun ke` to get the value `va` returned. But if that is their goal, they'll have to enhance your function. Good luck to all! – shellter Sep 26 '20 at 16:26
  • ah ok you're too kind :) – Nickotine Sep 26 '20 at 21:18