Lesson 6: Arrays & Data Structures

Goal: Use indexed and associative arrays for managing collections of data.


Table of Contents

  1. Indexed Arrays
  2. Array Operations
  3. Iterating Over Arrays
  4. Associative Arrays (Dictionaries)
  5. Practical Examples
  6. Exercises

Indexed Arrays

# Define an array
FRUITS=("apple" "banana" "cherry" "date")

# Access elements (0-indexed)
echo "${FRUITS[0]}"     # apple
echo "${FRUITS[2]}"     # cherry

# All elements
echo "${FRUITS[@]}"     # apple banana cherry date

# Array length
echo "${#FRUITS[@]}"    # 4

# Last element
echo "${FRUITS[-1]}"    # date

Creating arrays

# Method 1: Direct assignment
COLORS=("red" "green" "blue")

# Method 2: One at a time
FILES=()
FILES+=("config.yaml")
FILES+=("docker-compose.yml")
FILES+=("Makefile")

# Method 3: From command output
USERS=($(cut -d: -f1 /etc/passwd | head -5))

# Method 4: Read from file into array
mapfile -t LINES < /etc/hostname

Array Operations

ARR=("a" "b" "c" "d" "e")

# Append
ARR+=("f")

# Remove element at index 2
unset ARR[2]

# Slice (2 elements starting at index 1)
echo "${ARR[@]:1:2}"

# Replace element
ARR[0]="A"

# Check if array contains element
if [[ " ${ARR[*]} " == *" b "* ]]; then
    echo "Array contains 'b'"
fi

# String join (with delimiter)
IFS=','; echo "${ARR[*]}"; unset IFS

Iterating Over Arrays

SERVERS=("web01" "web02" "db01" "cache01")

# Standard loop
for server in "${SERVERS[@]}"; do
    echo "Server: $server"
done

# With index
for i in "${!SERVERS[@]}"; do
    echo "[$i] ${SERVERS[$i]}"
done

Always use "${array[@]}" with quotes to handle elements with spaces correctly.


Associative Arrays (Dictionaries)

Bash 4+ supports key-value pairs.

# Declare (required for associative arrays!)
declare -A CONFIG

CONFIG[host]="localhost"
CONFIG[port]="5432"
CONFIG[database]="myapp"
CONFIG[user]="admin"

echo "${CONFIG[host]}:${CONFIG[port]}"  # localhost:5432

# All keys
echo "${!CONFIG[@]}"    # host port database user

# All values
echo "${CONFIG[@]}"     # localhost 5432 myapp admin

# Iterate
for key in "${!CONFIG[@]}"; do
    echo "$key = ${CONFIG[$key]}"
done

Inline declaration

declare -A STATUS=(
    [web01]="running"
    [web02]="stopped"
    [db01]="running"
)

for server in "${!STATUS[@]}"; do
    echo "$server: ${STATUS[$server]}"
done

Practical Examples

Deploy to multiple servers

#!/bin/bash
set -euo pipefail

SERVERS=("web01.example.com" "web02.example.com" "web03.example.com")
DEPLOY_DIR="/var/www/app"

for server in "${SERVERS[@]}"; do
    echo "Deploying to $server..."
    rsync -avz --delete ./dist/ "deploy@${server}:${DEPLOY_DIR}/" || {
        echo "Failed: $server" >&2
        continue
    }
    echo "Done: $server"
done

Environment-based configuration

#!/bin/bash
set -euo pipefail
declare -A PORTS=(
    [nginx]="80"
    [api]="3000"
    [postgres]="5432"
    [redis]="6379"
)

echo "Service ports:"
for service in "${!PORTS[@]}"; do
    port="${PORTS[$service]}"
    if ss -tlnp | grep -q ":${port} " 2>/dev/null; then
        echo "  $service (:$port) — LISTENING"
    else
        echo "  $service (:$port) — not running"
    fi
done

Exercises

Exercise 1: Array basics

cat > arrays.sh << 'EOF'
#!/bin/bash
set -euo pipefail

LANGS=("Bash" "Python" "Go" "TypeScript" "Rust")

echo "Languages: ${LANGS[@]}"
echo "Count: ${#LANGS[@]}"
echo "First: ${LANGS[0]}"
echo "Last: ${LANGS[-1]}"

LANGS+=("Java")
echo "After append: ${LANGS[@]}"

for i in "${!LANGS[@]}"; do
    echo "  [$i] ${LANGS[$i]}"
done
EOF

chmod +x arrays.sh && ./arrays.sh
rm arrays.sh

Exercise 2: Associative array config

cat > config-check.sh << 'EOF'
#!/bin/bash
set -euo pipefail

declare -A REQUIRED_COMMANDS=(
    [git]="Version control"
    [docker]="Container runtime"
    [curl]="HTTP client"
    [jq]="JSON processor"
    [node]="JavaScript runtime"
)

echo "=== Dependency Check ==="
missing=0
for cmd in "${!REQUIRED_COMMANDS[@]}"; do
    desc="${REQUIRED_COMMANDS[$cmd]}"
    if command -v "$cmd" &>/dev/null; then
        echo "  [OK]      $cmd — $desc"
    else
        echo "  [MISSING] $cmd — $desc"
        ((missing++)) || true
    fi
done

echo ""
if ((missing > 0)); then
    echo "$missing dependencies missing!"
else
    echo "All dependencies satisfied!"
fi
EOF

chmod +x config-check.sh && ./config-check.sh
rm config-check.sh

Key Takeaways

  • ARR=("a" "b" "c") — indexed array
  • declare -A MAP — associative array (must declare)
  • "${ARR[@]}" — all elements (always quote!)
  • ${#ARR[@]} — length
  • ${!ARR[@]} — all keys/indices
  • ARR+=("new") — append
  • Associative arrays require Bash 4+

Next Lesson: Lesson 7: Text Processing in Scripts →