# 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](/upgrade-to-bash-4-in-mac-os-x) before running these
examples.

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

```bash
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:

```bash
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:

```bash
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:

```bash
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:

```bash
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:

```bash
names[Zaphod]=Beeblebrox
```

Assigning an existing key changes its value:

```bash
names[John]=Smith
```

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

```bash
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:

```bash
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:

```shell
$ man bash
```

Then search for `Arrays` inside the manual.
