438

Based on an associative array in a Bash script, I need to iterate over it to get the key and value.

#!/bin/bash

declare -A array
array[foo]=bar
array[bar]=foo

I actually don't understand how to get the key while using a for-in loop.

codeforester
  • 39,467
  • 16
  • 112
  • 140
pex
  • 7,351
  • 4
  • 32
  • 41
  • 23
    $ declare -A array=( [foo]=bar [bar]=foo ) # Initialise all at once – anisbet Jan 24 '14 at 16:26
  • 4
    For a small list of key values you might consider this: `for i in a,b c_s,d ; do KEY=${i%,*}; VAL=${i#*,}; echo $KEY" XX "$VAL; done` – math May 16 '14 at 14:45
  • Zsh counterpart (spoiler: it's way simpler in Zsh!): https://superuser.com/questions/737350/iterating-over-keys-or-k-v-pairs-in-zsh-associative-array – Franklin Yu Mar 23 '23 at 20:40
  • @math I like the simplicity of it, please consider making it a full fledged reply – Maxim Ky Mar 24 '23 at 07:32

5 Answers5

712

The keys are accessed using an exclamation point: ${!array[@]}, the values are accessed using ${array[@]}.

You can iterate over the key/value pairs like this:

for i in "${!array[@]}"
do
  echo "key  : $i"
  echo "value: ${array[$i]}"
done

Note the use of quotes around the variable in the for statement (plus the use of @ instead of *). This is necessary in case any keys include spaces.

The confusion in the other answer comes from the fact that your question includes "foo" and "bar" for both the keys and the values.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • 4
    This is now if assign all keys to an array: `array=(${!hash[@]})` – Michael-O Jun 06 '13 at 10:54
  • 16
    @Michael-O: You need to quote the parameter expansion to protect keys that may have whitespace: `array=("${!hash[@]}")` – Dennis Williamson May 22 '14 at 17:05
  • @DennisWilliamson, thanks a lot. I didn't have this on my mind. – Michael-O May 23 '14 at 07:07
  • 1
    How can we use a function argument number instead of a variable? e.g. `for i in "${!$1[@]}"` ? – pkaramol Feb 02 '18 at 10:44
  • 4
    @pkaramol: Starting in Bash 4.3 you can use namerefs. Example: `declare -A aa; aa['A']=a1; aa['B']=b2; aa['C']=c3; foo () { declare -n assoc=$1; for key in "${!assoc[@]}"; do echo "Key: $key; Value: ${assoc[$key]}"; done; }; foo aa`. Please see [BashFAQ/006](https://mywiki.wooledge.org/BashFAQ/006) for some important information. – Dennis Williamson Feb 02 '18 at 19:38
  • Is there any reference where this can be read, or is this from the man pages? I'm looking at the advanced bash scripting guide, but find it hard to get concise information. It doesn't even mention associative arrays. OK, I found this information in man bash – Werner Erasmus May 09 '20 at 09:29
  • Additional official [documentation](https://www.gnu.org/software/bash/manual/html_node/Arrays.html#Arrays). – Dennis Williamson Jun 28 '22 at 20:26
60

You can access the keys with ${!array[@]}:

bash-4.0$ echo "${!array[@]}"
foo bar

Then, iterating over the key/value pairs is easy:

for i in "${!array[@]}"
do
  echo "key :" $i
  echo "value:" ${array[$i]}
done
tonio
  • 10,355
  • 2
  • 46
  • 60
13

Use this higher order function to prevent the pyramid of doom

foreach(){ 
  arr="$(declare -p $1)" ; eval "declare -A f="${arr#*=}; 
  for i in ${!f[@]}; do $2 "$i" "${f[$i]}"; done
}

example:

$ bar(){ echo "$1 -> $2"; }
$ declare -A foo["flap"]="three four" foo["flop"]="one two"
$ foreach foo bar
flap -> three four
flop -> one two
coderofsalvation
  • 1,764
  • 16
  • 13
5

Welcome to input associative array 2.0!

    clear
    echo "Welcome to input associative array 2.0! (Spaces in keys and values now supported)"
    unset array
    declare -A array
    read -p 'Enter number for array size: ' num
    for (( i=0; i < num; i++ ))
        do
            echo -n "(pair $(( $i+1 )))"
            read -p ' Enter key: ' k
            read -p '         Enter value: ' v
            echo " "
            array[$k]=$v
        done
    echo " "
    echo "The keys are: " ${!array[@]}
    echo "The values are: " ${array[@]}
    echo " "
    echo "Key <-> Value"
    echo "-------------"
    for i in "${!array[@]}"; do echo $i "<->" ${array[$i]}; done
    echo " "
    echo "Thanks for using input associative array 2.0!"

Output:

Welcome to input associative array 2.0! (Spaces in keys and values now supported)
Enter number for array size: 4
(pair 1) Enter key: Key Number 1
         Enter value: Value#1

(pair 2) Enter key: Key Two
         Enter value: Value2

(pair 3) Enter key: Key3
         Enter value: Val3

(pair 4) Enter key: Key4
         Enter value: Value4


The keys are:  Key4 Key3 Key Number 1 Key Two
The values are:  Value4 Val3 Value#1 Value2

Key <-> Value
-------------
Key4 <-> Value4
Key3 <-> Val3
Key Number 1 <-> Value#1
Key Two <-> Value2

Thanks for using input associative array 2.0!

Input associative array 1.0

(keys and values that contain spaces are not supported)

    clear
    echo "Welcome to input associative array! (written by mO extraordinaire!)"
    unset array
    declare -A array
    read -p 'Enter number for array size: ' num
    for (( i=0; i < num; i++ ))
        do
            read -p 'Enter key and value separated by a space: ' k v
            array[$k]=$v
        done
    echo " "
    echo "The keys are: " ${!array[@]}
    echo "The values are: " ${array[@]}
    echo " "
    echo "Key <-> Value"
    echo "-------------"
    for i in ${!array[@]}; do echo $i "<->" ${array[$i]}; done
    echo " "
    echo "Thanks for using input associative array!"

Output:

Welcome to input associative array! (written by mO extraordinaire!)
Enter number for array size: 10
Enter key and value separated by a space: a1 10
Enter key and value separated by a space: b2 20
Enter key and value separated by a space: c3 30
Enter key and value separated by a space: d4 40
Enter key and value separated by a space: e5 50
Enter key and value separated by a space: f6 60
Enter key and value separated by a space: g7 70
Enter key and value separated by a space: h8 80
Enter key and value separated by a space: i9 90
Enter key and value separated by a space: j10 100

The keys are:  h8 a1 j10 g7 f6 e5 d4 c3 i9 b2
The values are:  80 10 100 70 60 50 40 30 90 20

Key <-> Value
-------------
h8 <-> 80
a1 <-> 10
j10 <-> 100
g7 <-> 70
f6 <-> 60
e5 <-> 50
d4 <-> 40
c3 <-> 30
i9 <-> 90
b2 <-> 20

Thanks for using input associative array!
mOmOney
  • 333
  • 3
  • 5
-2
declare -a arr
echo "-------------------------------------"
echo "Here another example with arr numeric"
echo "-------------------------------------"
arr=( 10 200 3000 40000 500000 60 700 8000 90000 100000 )

echo -e "\n Elements in arr are:\n ${arr[0]} \n ${arr[1]} \n ${arr[2]} \n ${arr[3]} \n ${arr[4]} \n ${arr[5]} \n ${arr[6]} \n ${arr[7]} \n ${arr[8]} \n ${arr[9]}"

echo -e " \n Total elements in arr are : ${arr[*]} \n"

echo -e " \n Total lenght of arr is : ${#arr[@]} \n"

for (( i=0; i<10; i++ ))
do      echo "The value in position $i for arr is [ ${arr[i]} ]"
done

for (( j=0; j<10; j++ ))
do      echo "The length in element $j is ${#arr[j]}"
done

for z in "${!arr[@]}"
do      echo "The key ID is $z"
done
~
Joel
  • 1,564
  • 7
  • 12
  • 20
EJISRHA
  • 17
  • 3