Arrays & Associative Maps

Indexed Arrays

An indexed array maps integer subscripts to strings. Subscripts start at 0 and do not have to be contiguous.

Creating an Array

fruits=(apple banana cherry)         # three elements, indices 0..2
fruits+=(date)                      # append one element
declare -a caps                     # explicit declaration
caps[0]=A; caps[2]=C                # sparse: index 1 is unset
fruits=(apple banana cherry) is three elements. fruits=("apple banana cherry") is one element. Spaces separate; quotes bind.

Accessing Elements

echo "${fruits[0]}"      # apple
echo "${fruits[-1]}"     # date   (last element, Bash 4.3+)
echo "${fruits[@]}"      # all elements as separate words
echo "${fruits[*]}"      # all elements joined into one word
echo "${#fruits[@]}"     # number of elements
echo "${!fruits[@]}"     # the indices themselves

Always quote "${arr[@]}". Unquoted ${arr[@]} re-splits each element on spaces, exactly like a bare $var.

Slicing

set -- one two three four
echo "${@:2:2}"                    # two three  (2 elements from index 2)
a=(10 20 30 40 50)
echo "${a[@]:1:3}"                 # 20 30 40

Iterating

for f in "${fruits[@]}"; do
  printf 'item: %s\n' "$f"        # one iteration per element, spaces safe
done

for i in "${!fruits[@]}"; do
  printf '%d -> %s\n' "$i" "${fruits[i]}"
done

Modifying and Removing

fruits[1]="blueberry"    # replace
unset 'fruits[2]'        # delete index 2 (quote it! otherwise glob risk)
fruits=()                # empty the whole array

Associative Arrays

Declared with declare -A, associative arrays use arbitrary string keys. They are the closest thing Bash has to a dictionary.

Declaring and Filling

declare -A score
score[alice]=90
score[bob]=75
score+=( [carol]=88 [dave]=64 )     # add several at once
You must declare with declare -A before the first assignment. Without it Bash creates an indexed array and score[alice] silently evaluates to index 0.

Reading and Iterating

echo "${score[alice]}"        # 90
echo "${#score[@]}"           # 4
for k in "${!score[@]}"; do
  printf '%-6s %s\n' "$k" "${score[$k]}"
done

A Practical Lookup Table

declare -A ext=(
  [sh]="shell"   [py]="python"
  [js]="javascript"  [bash]="shell"
)

describe() {
  local f="$1" e="${1##*.}"
  printf '%s -> %s\n' "$f" "${ext[$e]:-unknown}"
}
describe notes.py       # notes.py -> python
describe run.sh         # run.sh -> shell

Pitfalls

  • Unquoted [@]: splits elements on spaces — always "${arr[@]}".
  • Bash 3.2 on macOS: no associative arrays and no negative indices. Install a newer Bash or avoid those features.
  • Passing arrays to functions: a function cannot see your array by name across a subshell; pass "${arr[@]}" as arguments and rebuild with local -a copy=("$@").
  • Sparse arrays: ${#a[@]} counts set elements, not the highest index + 1.