Bash Arrays: A Comprehensive Guide with Examples
Arrays are one of the most powerful features in Bash scripting, allowing you to store and manipulate collections of data efficiently. This comprehensive guide explores everything you need to know about Bash arrays, from basic concepts to advanced techniques.
Table of Contents
- Introduction to Bash Arrays
- Types of Arrays in Bash
- Creating Arrays
- Accessing Array Elements
- Modifying Arrays
- Array Operations
- Practical Examples
- Common Errors and Troubleshooting
- Best Practices
- Conclusion
Introduction to Bash Arrays
Bash arrays provide a way to group multiple values under a single variable name. Unlike many programming languages, Bash arrays can contain mixed data types and don’t require declaration with a specific size.
Why Use Arrays?
- Organize related data: Group similar items together
- Iterate efficiently: Process multiple values with loops
- Simplify code: Reduce repetition and improve readability
- Dynamic data handling: Add or remove elements as needed
Types of Arrays in Bash
Bash supports two types of arrays:
1. Indexed Arrays
Indexed arrays use numeric indices starting from 0. They’re the most common type and available in all Bash versions.
# Example of indexed array
fruits=("apple" "banana" "orange")
echo ${fruits[0]} # Output: apple
2. Associative Arrays
Associative arrays use string keys instead of numeric indices. They require Bash 4.0 or later.
# Example of associative array
declare -A colors
colors[red]="#FF0000"
colors[green]="#00FF00"
echo ${colors[red]} # Output: #FF0000
Creating Arrays
There are multiple ways to create arrays in Bash:
Method 1: Direct Assignment
# Creating an indexed array
fruits=("apple" "banana" "orange" "grape")
# Creating an associative array
declare -A user_info
user_info[name]="John Doe"
user_info[email]="[email protected]"
Method 2: Individual Element Assignment
# Indexed array
numbers[0]=10
numbers[1]=20
numbers[2]=30
# Associative array
declare -A config
config[host]="localhost"
config[port]=8080
Method 3: Read from Command Output
# Create array from command output
files=($(ls *.txt))
# Using readarray (Bash 4+)
readarray -t lines < file.txt
Method 4: Using declare
# Declare an indexed array
declare -a my_array
# Declare an associative array
declare -A my_map
Accessing Array Elements
Individual Elements
# Indexed array
echo ${fruits[0]} # First element
echo ${fruits[2]} # Third element
# Associative array
echo ${user_info[name]}
echo ${user_info[email]}
All Elements
# All elements
echo ${fruits[@]} # All elements separated by space
echo ${fruits[*]} # All elements as a single string
# With quotes to preserve spaces
echo "${fruits[@]}" # Each element as separate word
Array Length
# Number of elements
echo ${#fruits[@]}
# Length of specific element
echo ${#fruits[0]} # Length of first element
Array Indices
# Get all indices
echo ${!fruits[@]} # For indexed arrays: 0 1 2 3
echo ${!user_info[@]} # For associative arrays: name email
Modifying Arrays
Adding Elements
# Append to array
fruits+=("mango")
fruits+=("peach" "plum")
# Add at specific index
fruits[10]="watermelon"
# Associative array
user_info[age]=30
Updating Elements
# Update existing element
fruits[1]="blackberry"
user_info[email]="[email protected]"
Removing Elements
# Unset individual element
unset fruits[2]
unset user_info[age]
# Clear entire array
unset fruits
unset user_info
Slicing Arrays
# Get subset of array
subset=("${fruits[@]:1:3}") # Starting at index 1, get 3 elements
Array Operations
Iterating Over Arrays
# Iterate over values
for fruit in "${fruits[@]}"; do
echo "Fruit: $fruit"
done
# Iterate over indices
for i in "${!fruits[@]}"; do
echo "Index $i: ${fruits[$i]}"
done
# Iterate over associative array
for key in "${!user_info[@]}"; do
echo "$key: ${user_info[$key]}"
done
Searching Arrays
# Check if element exists
contains() {
local element="$1"
shift
local array=("$@")
for item in "${array[@]}"; do
[[ "$item" == "$element" ]] && return 0
done
return 1
}
# Usage
if contains "apple" "${fruits[@]}"; then
echo "Found apple!"
fi
Sorting Arrays
# Sort array
IFS=$'\n' sorted=($(sort <<<"${fruits[*]}"))
unset IFS
Filtering Arrays
# Filter array elements
filtered=()
for fruit in "${fruits[@]}"; do
if [[ ${#fruit} -gt 5 ]]; then
filtered+=("$fruit")
fi
done
Practical Examples
Example 1: File Processing
#!/bin/bash
# Process multiple files
files=("data1.txt" "data2.txt" "data3.txt")
results=()
for file in "${files[@]}"; do
if [[ -f "$file" ]]; then
line_count=$(wc -l < "$file")
results+=("$file: $line_count lines")
else
results+=("$file: not found")
fi
done
# Display results
printf '%s\n' "${results[@]}"
Example 2: Configuration Management
#!/bin/bash
# Configuration using associative array
declare -A config
config[db_host]="localhost"
config[db_port]=5432
config[db_name]="myapp"
config[db_user]="appuser"
# Function to get config value
get_config() {
local key="$1"
echo "${config[$key]:-}"
}
# Build connection string
connection="postgresql://$(get_config db_user)@$(get_config db_host):$(get_config db_port)/$(get_config db_name)"
echo "Connection: $connection"
Example 3: Menu System
#!/bin/bash
# Menu options
options=("Start Service" "Stop Service" "Restart Service" "Check Status" "Exit")
# Display menu
show_menu() {
echo "Service Manager"
echo "==============="
for i in "${!options[@]}"; do
echo "$((i+1)). ${options[$i]}"
done
}
# Main loop
while true; do
show_menu
read -p "Select option: " choice
case $choice in
1) echo "Starting service...";;
2) echo "Stopping service...";;
3) echo "Restarting service...";;
4) echo "Checking status...";;
5) echo "Goodbye!"; exit 0;;
*) echo "Invalid option";;
esac
echo
done
Example 4: Data Analysis
#!/bin/bash
# Temperature data
declare -A temperatures
temperatures[Monday]=72
temperatures[Tuesday]=75
temperatures[Wednesday]=78
temperatures[Thursday]=71
temperatures[Friday]=73
# Calculate statistics
sum=0
count=0
max_temp=0
min_temp=999
max_day=""
min_day=""
for day in "${!temperatures[@]}"; do
temp=${temperatures[$day]}
((sum += temp))
((count++))
if ((temp > max_temp)); then
max_temp=$temp
max_day=$day
fi
if ((temp < min_temp)); then
min_temp=$temp
min_day=$day
fi
done
# Calculate average
average=$((sum / count))
# Display results
echo "Temperature Analysis"
echo "===================="
echo "Average: $average°F"
echo "Highest: $max_temp°F on $max_day"
echo "Lowest: $min_temp°F on $min_day"
Common Errors and Troubleshooting
Error 1: Unbound Variable
# Problem
echo ${fruits[10]} # May cause error if index doesn't exist
# Solution
echo ${fruits[10]:-"default"} # Provide default value
Error 2: Word Splitting
# Problem
files=($(ls)) # Breaks on filenames with spaces
# Solution
readarray -d '' files < <(find . -type f -print0)
Error 3: Associative Array Declaration
# Problem
user_info[name]="John" # Won't work without declaration
# Solution
declare -A user_info
user_info[name]="John"
Error 4: Array Assignment
# Problem
array=$other_array # Assigns first element only
# Solution
array=("${other_array[@]}") # Copy entire array
Best Practices
1. Always Use Quotes
# Good
for item in "${array[@]}"; do
echo "$item"
done
# Bad
for item in ${array[@]}; do
echo $item
done
2. Check Array Length
# Check if array is empty
if [[ ${#array[@]} -eq 0 ]]; then
echo "Array is empty"
fi
3. Use Meaningful Names
# Good
server_names=("web01" "web02" "db01")
# Bad
arr=("web01" "web02" "db01")
4. Initialize Arrays
# Initialize empty array
declare -a my_array=()
declare -A my_map=()
5. Document Array Purpose
# User roles and permissions
declare -A user_roles=(
[admin]="read,write,delete"
[editor]="read,write"
[viewer]="read"
)
6. Use Functions for Complex Operations
# Function to add unique elements
add_unique() {
local -n arr=$1
local element=$2
if ! contains "$element" "${arr[@]}"; then
arr+=("$element")
fi
}
Advanced Techniques
Passing Arrays to Functions
# Pass by reference (Bash 4.3+)
process_array() {
local -n arr=$1
for item in "${arr[@]}"; do
echo "Processing: $item"
done
}
# Usage
my_array=("a" "b" "c")
process_array my_array
Multi-dimensional Arrays (Simulation)
# Simulate 2D array
declare -A matrix
matrix[0,0]="A"
matrix[0,1]="B"
matrix[1,0]="C"
matrix[1,1]="D"
# Access elements
echo ${matrix[0,1]} # Output: B
Array Serialization
# Save array to file
declare -p fruits > array_backup.sh
# Load array from file
source array_backup.sh
Conclusion
Bash arrays are versatile tools that can significantly improve your shell scripts. By understanding both indexed and associative arrays, you can write more efficient and maintainable code. Remember to follow best practices, handle edge cases properly, and choose the right type of array for your specific use case.
Whether you’re processing files, managing configurations, or analyzing data, arrays provide the flexibility and power needed for complex bash scripting tasks. With the examples and techniques covered in this guide, you’re well-equipped to leverage arrays effectively in your shell scripts.