Arrays in Bash — Indexed and Associative
Store multiple values in a single variable. Bash supports both indexed arrays (like lists) and associative arrays (like dictionaries). Understand how to create, access, loop, and slice them.
Bash arrays let you store a collection of values in one variable. There are two kinds: indexed arrays (zero-based integer indices, like a list) and associative arrays (string keys, like a dict). Both are essential for writing non-trivial scripts.
Indexed Arrays
# Declare and initialize
fruits=("apple" "banana" "cherry" "date")
# Access individual elements (0-based index)
echo "${fruits[0]}" # apple
echo "${fruits[2]}" # cherry
# Get all elements
echo "${fruits[@]}" # apple banana cherry date
# Number of elements
echo "${#fruits[@]}" # 4
# Get all indices
echo "${!fruits[@]}" # 0 1 2 3
# Slice: elements 1 and 2 (start index, count)
echo "${fruits[@]:1:2}" # banana cherry# Add elements
fruits+=("elderberry") # append
fruits[10]="fig" # sparse assignment (leaves gaps)
# Modify element
fruits[1]="blueberry"
# Delete element
unset fruits[2] # removes cherry, leaves gap
echo "${!fruits[@]}" # 0 1 3 4 10 (gap at index 2)
# Delete entire array
unset fruitsLooping Over Arrays
colors=("red" "green" "blue")
# Loop over values (most common)
for color in "${colors[@]}"; do
echo "Color: $color"
done
# Loop with index
for i in "${!colors[@]}"; do
echo "[$i] ${colors[$i]}"
done
# [0] red
# [1] green
# [2] blueAlways use "${array[@]}" with quotes
${array[@]} expands to all elements as separate words, preserving elements that contain spaces.
${array[*]} expands to all elements joined into one string.
Without quotes: ${array[@]} behaves like ${array[*]} — both split on whitespace, corrupting elements with spaces.
Rule: Always write "${array[@]}" (with double quotes) in loops and when passing to commands.
Read Lines into an Array
# mapfile (or readarray) reads lines from stdin into an array
mapfile -t lines < /etc/hosts # each line becomes an element (-t trims newlines)
echo "Total lines: ${#lines[@]}"
# Or from command output
mapfile -t files < <(find /tmp -name "*.log" -maxdepth 1)
# Process them
for f in "${files[@]}"; do
echo "Processing: $f"
doneAssociative Arrays (Bash 4+)
Associative arrays use string keys instead of integer indices. They must be explicitly declared with declare -A.
declare -A user
user["name"]="Alice"
user["age"]="30"
user["role"]="admin"
# Access
echo "${user["name"]}" # Alice
echo "${user[role]}" # admin (quotes around key optional)
# All keys
echo "${!user[@]}" # name age role (unordered)
# All values
echo "${user[@]}" # Alice 30 admin (unordered)
# Check if key exists
if [[ -v user["email"] ]]; then
echo "email is set"
else
echo "email not set"
fi
# Loop over key-value pairs
for key in "${!user[@]}"; do
echo "$key = ${user[$key]}"
donePractical — Counting Words
#!/usr/bin/env bash
# Count word frequency in a file using an associative array
declare -A counts
while read -r word; do
word="${word,,}" # lowercase
word="${word//[^a-z]/}" # remove non-alpha chars
[[ -z "$word" ]] && continue
(( counts["$word"]++ ))
done < <(tr ' ' '
' < "${1:-/dev/stdin}")
# Print sorted by count (desc)
for word in "${!counts[@]}"; do
echo "${counts[$word]} $word"
done | sort -rn | head -10What must you do before using an associative array in Bash?
Create a script that:
- Stores three server names and their IPs in an associative array
- Loops over them and prints "Server: web1 → IP: 192.168.1.1"
- Checks if a server named "db2" exists and prints an appropriate message