Share on Mastodon

Quick reference of things I discovered about how to use associative arrays in bash. Note: bash version 4 only.

Play my Android game Rabbit Escape!

Update: see also Bash Arrays.

Basics

$ declare -A MYMAP # Create an associative array $ MYMAP[foo]=bar # Put a value into an associative array $ echo ${MYMAP[foo]} # Get a value out of an associative array bar $ echo MYMAP[foo] # WRONG MYMAP[foo] $ echo $MYMAP[foo] # WRONG [foo]

Creating

$ declare -A MYMAP # Explicitly declare $ MYMAP[foo]=bar # Or this line implicitly makes it an associative array (in global scope, bash 4.2+ only) $ MYMAP[baz]=quux # Can add multiple values one by one $ MYMAP[corge]=grault

$ declare -A MYMAP=( [foo]=bar [baz]=quux [corge]=grault ) # Initialise all at once $ echo ${MYMAP[foo]} bar $ echo ${MYMAP[baz]} quux

$ declare -A MYMAP # Or declare separately $ MYMAP=( [foo]=bar [baz]=quux [corge]=grault ) # Then initialise $ echo ${MYMAP[foo]} bar $ echo ${MYMAP[baz]} quux

Variables as keys

$ K=baz $ MYMAP[$K]=quux # Use a variable as key to put a value into an associative array $ echo ${MYMAP[$K]} # Use a variable as key to extract a value from an associative array quux $ echo ${MYMAP[baz]} # Obviously the value is accessible via the literal key quux

Quoting keys

$ declare -A MYMAP $ MYMAP[foo A]="bar B" # Quoting keys makes no difference $ MYMAP["corge X"]="grault Y" # Quoting keys makes no difference $ echo ${MYMAP["corge X"]} # You can access by quoting grault Y $ echo ${MYMAP[corge X]} # Or not bother grault Y $ echo ${MYMAP[foo A]} bar B $ MYMAP['waldo 1']="fred 2" # Single quotes also make no difference $ echo ${MYMAP['waldo 1']} fred 2 $ echo ${MYMAP[waldo 1]} fred 2 $ K=plugh $ MYMAP['$K']=xyzzy # Except single quotes prevent variable expansion, as usual $ echo ${MYMAP[plugh]} $ echo ${MYMAP['$K']} xyzzy

Missing keys

$ MYMAP[foo]=bar $ echo ${MYMAP[missing]} # Accessing a missing value gives "" $ # Testing whether a value is missing from an associative array $ if [ ${MYMAP[foo]+_} ]; then echo "Found"; else echo "Not found"; fi Found $ if [ ${MYMAP[missing]+_} ]; then echo "Found"; else echo "Not found"; fi Not found

Looping

$ declare -A MYMAP=( [foo a]=bar [baz b]=quux ) $ echo "${!MYMAP[@]}" # Print all keys - quoted, but quotes removed by echo foo a baz b $ # Loop through all keys in an associative array $ for K in "${!MYMAP[@]}"; do echo $K; done foo a baz b $ for K in ${!MYMAP[@]}; do echo $K; done # WRONG foo a baz b $ # Looping through keys and values in an associative array $ for K in "${!MYMAP[@]}"; do echo $K --- ${MYMAP[$K]}; done foo a --- bar baz b --- quux $ # Loop through all values in an associative array $ for V in "${MYMAP[@]}"; do echo $V; done bar quux

Clearing

$ declare -A MYMAP $ MYMAP[foo]=bar $ echo ${MYMAP[foo]} bar $ declare -A MYMAP # Re-declaring DOES NOT clear an associative array $ echo ${MYMAP[foo]} bar $ unset MYMAP # You need to unset and re-declare to get a cleared associative array $ declare -A MYMAP $ echo ${MYMAP[foo]}

Deleting keys

$ MYMAP[foo]=bar $ echo ${MYMAP[foo]} bar $ unset ${MYMAP[foo]} # WRONG $ echo ${MYMAP[foo]} bar $ unset MYMAP[foo] # To delete from an associative array, use "unset" with similar syntax to assigning $ # BUT see next section if key contains spaces $ echo ${MYMAP[foo]} $ MYMAP[baz]=quux $ echo ${MYMAP[baz]} quux $ K=baz $ unset MYMAP[$K] # Can unset using a variable for the key too $ # BUT see next section if variable may contain spaces - always better to quote $ echo ${MYMAP[baz]}

Deleting keys containing spaces

$ declare -A MYMAP $ MYMAP[foo Z]=bar $ echo ${MYMAP[foo Z]} bar $ unset MYMAP[foo Z] # WRONG bash: unset: `MYMAP[foo': not a valid identifier bash: unset: `Z]': not a valid identifier $ unset MYMAP["foo Z"] # You must quote keys containing spaces when you unset in an associative array $ echo ${MYMAP[foo Z]} $ MYMAP[foo Z]=bar $ unset MYMAP['foo Z'] # Single quotes work too $ echo ${MYMAP[foo Z]} $ MYMAP[baz A]=quux $ echo ${MYMAP[baz A]} quux $ K="baz A" $ unset MYMAP[$K] # WRONG bash: unset: `MYMAP[baz': not a valid identifier bash: unset: `A]': not a valid identifier $ unset MYMAP["$K"] # You must quote variables whose values may contain spaces when you unset in an associative array $ echo ${MYMAP[baz A]} $ MYMAP[baz A]=quux $ unset MYMAP['$K'] # Curiously, single quotes work here too, although I'd suggest avoiding them $ echo ${MYMAP[baz A]}

Length

$ declare -A MYMAP=( [foo a]=bar [baz b]=quux ) $ echo ${#MYMAP[@]} # Number of keys in an associative array 2 $ echo $#MYMAP[@] # WRONG 0MYMAP[@] $ echo ${#MYMAP} # WRONG 0

Numeric indexing

$ declare -A MYMAP=( [foo a]=bar [baz b]=quux ) $ KEYS=("${!MYMAP[@]}") # Make a normal array containing all the keys in the associative array $ echo ${KEYS[0]} # Find a key via an index foo a $ echo ${MYMAP[${KEYS[0]}]} # Find a value via an index bar $ # Loop through using an index $ for (( I=0; $I < ${#MYMAP[@]}; I+=1 )); do KEY=${KEYS[$I]}; echo $KEY --- ${MYMAP[$KEY]}; done foo a --- bar baz b --- quux

Scope

$ unset MYMAP $ function createmap() { MYMAP[foo]=bar; } # Implicit creation puts it in the global scope $ echo ${MYMAP[foo]} $ createmap $ echo ${MYMAP[foo]} bar

$ unset MYMAP $ function createmaplocal() { declare -A MYMAP; MYMAP[foo]=bar; } # Explicit creation puts it in the local scope $ echo ${MYMAP[foo]} $ createmaplocal $ echo ${MYMAP[foo]}

Checking Bash version

$ bash --version # Must be at least version 4 to have associative arrays GNU bash, version 4.2.24(1)-release (x86_64-pc-linux-gnu) ...

Links