Associative arrays in Bash

An associative array stores values under text keys instead of numbered positions. Bash 4.0 and newer support them.

On macOS, that may mean upgrading the system Bash before running these examples.

Here is an array that uses first names as keys and last names as values:

declare -A names=(
  [John]=Doe
  [Jane]=Doe
  [Jim]=Smith
  [Angela]=Merkel
)

The capital -A tells Bash that names is an associative array. Lowercase -a would create a regular indexed array instead.

Each entry has a key and a value:

  ┌── array name
  |          ┌── array value
┌─┴─┐       ┌┴┐
names[John]=Doe
     └──┬─┘
        └── array key

You can also declare the array first and add entries later:

declare -A names
names[John]=Doe
names[Jane]=Doe
names[Jim]=Smith
names[Angela]=Merkel

Read a value

Use its key to read a value:

printf '%s\n' "${names[John]}"
# Doe

Quote array expansions. This keeps spaces and wildcard characters in keys or values from being treated as shell syntax.

Loop over the array

${!names[@]} expands to all keys. Use each key to read its matching value:

for first_name in "${!names[@]}"; do
  last_name=${names[$first_name]}
  printf '%s : %s\n' "$first_name" "$last_name"
done

One possible output is:

John : Doe
Jane : Doe
Jim : Smith
Angela : Merkel

The order may differ between runs or Bash versions.

Find keys by value

Associative arrays are made for looking up a value by its key, not the other way around. More than one key can also have the same value: both John and Jane map to Doe in this example. To find matching keys, loop over the array:

wanted_last_name=Doe
 
for first_name in "${!names[@]}"; do
  if [[ ${names[$first_name]} == "$wanted_last_name" ]]; then
    printf '%s\n' "$first_name"
  fi
done

This prints John and Jane, though their order is not guaranteed.

Add, change, and remove entries

Assigning a new key adds an entry:

names[Zaphod]=Beeblebrox

Assigning an existing key changes its value:

names[John]=Smith

Remove an entry with unset. Quote the argument so the brackets are not read as a filename pattern:

unset 'names[Jim]'

Associative arrays do not have a fixed order, so adding an entry does not append it to an "end."

Keys and values with spaces

Quote keys and values that contain spaces:

declare -A couples=(
  ["John Doe"]="Jane Doe"
  ["David Hasselhoff"]="Angela Merkel"
)
 
person="John Doe"
printf '%s\n' "${couples[$person]}"
# Jane Doe

To read Bash's full documentation for arrays, run:

$ man bash

Then search for Arrays inside the manual.