Skip to content

Associative_arrays

Associative arrays in bash (available in Bash 4+) allow you to store data using key-value pairs. This is similar to dictionaries or hashes in other programming languages. This chapter covers declaring, accessing, and using associative arrays for DevOps configurations, caching, and data management.


assoc_declare.sh
#!/usr/bin/env bash
# Must declare before use (Bash 4+)
declare -A config
# Assign values
config[host]="localhost"
config[port]="8080"
config[database]="myapp"
config[debug]="true"
# Or initialize all at once
declare -A settings=(
[host]="localhost"
[port]="8080"
[database]="myapp"
[debug]="true"
)

assoc_access.sh
#!/usr/bin/env bash
declare -A user
user[name]="John Doe"
user[email]="john@example.com"
user[role]="admin"
# Access by key
echo "Name: ${user[name]}"
echo "Email: ${user[email]}"
echo "Role: ${user[role]}"
# Alternative syntax
echo "Name: ${user[name]}"
echo "Email: ${user[email]}"
assoc_keys.sh
#!/usr/bin/env bash
declare -A server
server[web01]="192.168.1.10"
server[web02]="192.168.1.11"
server[db01]="192.168.1.20"
# All keys
echo "Keys: ${!server[@]}"
# All values
echo "Values: ${server[@]}"
# Number of elements
echo "Count: ${#server[@]}"

assoc_iterate.sh
#!/usr/bin/env bash
declare -A colors
colors[red]="#FF0000"
colors[green]="#00FF00"
colors[blue]="#0000FF"
# Iterate over keys
echo "Servers:"
for key in "${!colors[@]}"; do
echo " $key = ${colors[$key]}"
done
# Iterate over values
echo "Colors:"
for value in "${colors[@]}"; do
echo " $value"
done

server_config.sh
#!/usr/bin/env bash
declare -A servers
# Web servers
servers[web01]="192.168.1.10"
servers[web02]="192.168.1.11"
servers[web03]="192.168.1.12"
# Database servers
servers[db01]="192.168.2.10"
servers[db02]="192.168.2.11"
# Cache servers
servers[cache01]="192.168.3.10"
echo "Server inventory:"
echo "=================="
# Group by type
for key in "${!servers[@]}"; do
ip="${servers[$key]}"
type="${key%%[0-9]*}"
printf "%-10s %-15s %s\n" "$type" "$key" "$ip"
done
env_config.sh
#!/usr/bin/env bash
# Configuration for different environments
declare -A prod_config
prod_config[db_host]="prod-db.example.com"
prod_config[db_port]="5432"
prod_config[max_connections]="200"
prod_config[log_level]="warn"
declare -A staging_config
staging_config[db_host]="staging-db.example.com"
staging_config[db_port]="5432"
staging_config[max_connections]="50"
staging_config[log_level]="debug"
declare -A dev_config
dev_config[db_host]="localhost"
dev_config[db_port]="5432"
dev_config[max_connections]="10"
dev_config[log_level]="debug"
# Function to load config
load_config() {
local env="$1"
local -n config="$env_config"
case "$env" in
production) config=prod_config ;;
staging) config=staging_config ;;
development) config=dev_config ;;
esac
echo "Loaded $env configuration:"
for key in "${!config[@]}"; do
echo " $key = ${config[$key]}"
done
}
# Usage
load_config "production"
cache.sh
#!/usr/bin/env bash
declare -A cache
declare -A cache_expiry
# Add to cache
cache_set() {
local key="$1"
local value="$2"
local ttl="${3:-300}" # Default 5 minutes
cache["$key"]="$value"
cache_expiry["$key"]=$(($(date +%s) + ttl))
}
# Get from cache
cache_get() {
local key="$1"
local now=$(date +%s)
# Check if key exists
if [ -z "${cache[$key]+exists}" ]; then
return 1 # Not found
fi
# Check if expired
if [ $now -gt ${cache_expiry[$key]:-0} ]; then
unset cache["$key"]
unset cache_expiry["$key"]
return 1 # Expired
fi
echo "${cache[$key]}"
return 0
}
# Clear cache
cache_clear() {
local key="$1"
unset cache["$key"]
unset cache_expiry["$key"]
}
# Usage
cache_set "user_123" "John Doe" 60
cache_get "user_123" && echo "Found" || echo "Not found"
sleep 2
cache_get "user_123" && echo "Found" || echo "Expired or not found"
metrics.sh
#!/usr/bin/env bash
declare -A metrics
# Record metric
record_metric() {
local name="$1"
local value="$2"
metrics["$name"]="$value"
}
# Get metric
get_metric() {
local name="$1"
echo "${metrics[$name]:-0}"
}
# Increment counter
increment_counter() {
local name="$1"
local current=${metrics[$name]:-0}
metrics["$name"]=$((current + 1))
}
# Record CPU usage
record_metric "cpu_usage" "45"
record_metric "memory_usage" "72"
record_metric "disk_usage" "68"
# Increment request counter
increment_counter "requests_total"
increment_counter "requests_total"
increment_counter "requests_total"
echo "Metrics:"
for key in "${!metrics[@]}"; do
echo " $key = ${metrics[$key]}"
done
flags.sh
#!/usr/bin/env bash
declare -A flags
# Parse flags
parse_flags() {
while [ $# -gt 0 ]; do
case "$1" in
-v|--verbose)
flags[verbose]=true
shift
;;
-f|--force)
flags[force]=true
shift
;;
-q|--quiet)
flags[quiet]=true
shift
;;
-o|--output)
flags[output]="$2"
shift 2
;;
*)
echo "Unknown flag: $1"
return 1
;;
esac
done
}
# Check flag
has_flag() {
local flag="$1"
[ "${flags[$flag]:-false}" = "true" ]
}
# Parse example flags
parse_flags -v -f --output /tmp/out.txt
# Check flags
if has_flag verbose; then
echo "Verbose mode enabled"
fi
if has_flag force; then
echo "Force mode enabled"
fi
echo "Output: ${flags[output]:-stdout}"
file_types.sh
#!/usr/bin/env bash
declare -A mime_types
# Initialize common types
mime_types[txt]="text/plain"
mime_types[html]="text/html"
mime_types[css]="text/css"
mime_types[js]="application/javascript"
mime_types[json]="application/json"
mime_types[pdf]="application/pdf"
mime_types[zip]="application/zip"
mime_types[png]="image/png"
mime_types[jpg]="image/jpeg"
mime_types[jpeg]="image/jpeg"
mime_types[gif]="image/gif"
mime_types[svg]="image/svg+xml"
mime_types[xml]="application/xml"
# Get MIME type
get_mime_type() {
local file="$1"
local ext="${file##*.}"
if [ -n "${mime_types[$ext]:-}" ]; then
echo "${mime_types[$ext]}"
else
echo "application/octet-stream"
fi
}
# Usage
for file in document.txt image.png script.js data.json; do
echo "$file -> $(get_mime_type "$file")"
done

assoc_exists.sh
#!/usr/bin/env bash
declare -A config
config[host]="localhost"
config[port]="8080"
# Check key exists
if [ -n "${config[host]+exists}" ]; then
echo "Key 'host' exists: ${config[host]}"
fi
# Check key doesn't exist
if [ -z "${config[debug]+exists}" ]; then
echo "Key 'debug' does not exist"
fi
assoc_delete.sh
#!/usr/bin/env bash
declare -A data
data[key1]="value1"
data[key2]="value2"
echo "Before: ${!data[@]}"
unset data[key1]
echo "After: ${!data[@]}"
assoc_copy.sh
#!/usr/bin/env bash
declare -A source
source[a]="1"
source[b]="2"
# Copy to destination
declare -A dest
for key in "${!source[@]}"; do
dest["$key"]="${source[$key]}"
done
echo "Copied: ${dest[@]}"

Terminal window
# Good: Descriptive keys
declare -A server_config
server_config[hostname]="web01"
server_config[ip_address]="192.168.1.10"
# Avoid: Cryptic keys
declare -A bad_config
bad_config[h]="web01"
bad_config[ip]="192.168.1.10"
Terminal window
# WRONG: May not work on all bash versions
config[key]="value"
# CORRECT: Always declare
declare -A config
config[key]="value"

In this chapter, you learned about:

  • ✅ Associative array declaration
  • ✅ Accessing values
  • ✅ Iterating over keys and values
  • ✅ Practical examples
  • ✅ Advanced operations
  • ✅ Best practices

  1. Create an associative array for user data
  2. Access and print all key-value pairs
  3. Check if a key exists
  1. Implement a configuration system
  2. Create a cache mechanism
  3. Build a metrics collector
  1. Implement a flag parser
  2. Create a file type mapping system
  3. Build a multi-environment configuration manager

Continue to the next chapter to learn about string manipulation.


Previous Chapter: Arrays Next Chapter: String Manipulation