How to Use Bash Arrays and Loops in Linux Shell Scripts

Bash arrays and loops are two of the most powerful tools in shell scripting. On their own, each command in a Bash script runs a single operation on a single piece of data. Arrays let you store and manage multiple values under one variable name. Loops let you repeat operations across those values automatically. Together, they allow you to write scripts that handle real-world tasks: processing lists of files, iterating over server names, transforming data from configuration files, or running the same operation across hundreds of items without repetition.

This guide covers how Bash arrays work, the types of loops available in Bash, and practical patterns that combine both for common scripting tasks.

Bash Arrays

Bash supports two types of arrays: indexed arrays (standard arrays with numeric indices starting at 0) and associative arrays (key-value pairs, available in Bash 4 and later).

Creating and Populating an Indexed Array

You can define an array in several ways:

# Define an array with values on a single line
servers=("web01" "web02" "db01" "cache01")

# Define an array and add values one by one
packages=()
packages+=("nginx")
packages+=("curl")
packages+=("git")

Access individual elements by index:

echo "${servers[0]}"   # Outputs: web01
echo "${servers[2]}"   # Outputs: db01

Access all elements with @ or *:

echo "${servers[@]}"   # Outputs all elements separated by spaces

Get the number of elements in an array:

echo "${#servers[@]}"  # Outputs: 4

Creating an Associative Array

Associative arrays use string keys instead of numeric indices. They must be declared explicitly:

declare -A config
config["host"]="192.168.1.100"
config["port"]="8080"
config["user"]="deploy"

echo "${config[host]}"    # Outputs: 192.168.1.100

Access all keys:

echo "${!config[@]}"   # Outputs: host port user

Bash Loops

Bash provides three main loop types: for, while, and until. Each suits different patterns of iteration.

The for Loop

The most common loop for iterating over a list of values or array elements:

# Loop over a static list
for fruit in apple banana cherry; do
    echo "Fruit: $fruit"
done

# Loop over an array
for server in "${servers[@]}"; do
    echo "Pinging: $server"
    ping -c 1 "$server" > /dev/null 2>&1 && echo "$server is up" || echo "$server is down"
done

The C-Style for Loop (Numeric Range)

For looping a specific number of times with a counter:

for ((i = 1; i <= 10; i++)); do
    echo "Iteration $i"
done

The while Loop

Repeats as long as a condition evaluates as true. Useful for reading input line by line or waiting for a condition:

# Read each line of a file into a variable
while IFS= read -r line; do
    echo "Line: $line"
done < "/etc/hosts"

The until Loop

The inverse of while — repeats until the condition becomes true:

count=0
until [ $count -ge 5 ]; do
    echo "Count is $count"
    ((count++))
done

Looping Over Array Indices

Sometimes you need both the index and the value. Use ${!array[@]} to iterate over indices:

files=("report.pdf" "data.csv" "config.yaml")

for i in "${!files[@]}"; do
    echo "File $i: ${files[$i]}"
done
# Outputs:
# File 0: report.pdf
# File 1: data.csv
# File 2: config.yaml

Practical Scripting Patterns

Batch File Processing

Process every file matching a pattern in a directory:

#!/bin/bash
for file in /var/log/*.log; do
    echo "Processing: $file"
    gzip "$file"
done

Reading Command Output into an Array

Capture the output of a command as an array for processing:

# Store all running process names in an array
mapfile -t processes < <(ps -eo comm= | sort -u)

for proc in "${processes[@]}"; do
    echo "$proc"
done

The mapfile (or readarray) command reads lines from standard input into an indexed array. The -t flag removes trailing newlines from each element.

Building a Simple Retry Loop

Retry a command up to a maximum number of attempts:

#!/bin/bash
max_attempts=5
attempt=1

while [ $attempt -le $max_attempts ]; do
    echo "Attempt $attempt of $max_attempts..."
    curl -s "https://example.com/api/health" && break
    echo "Failed. Retrying in 5 seconds..."
    sleep 5
    ((attempt++))
done

if [ $attempt -gt $max_attempts ]; then
    echo "Service did not respond after $max_attempts attempts."
    exit 1
fi

Looping Over an Associative Array

Process key-value configuration pairs:

declare -A env_vars
env_vars["DB_HOST"]="localhost"
env_vars["DB_PORT"]="5432"
env_vars["APP_ENV"]="production"

for key in "${!env_vars[@]}"; do
    echo "export $key='${env_vars[$key]}'"
done

Loop Control: break and continue

Use break to exit a loop early and continue to skip the current iteration and move to the next:

for number in 1 2 3 4 5 6 7 8 9 10; do
    if [ $number -eq 5 ]; then
        continue   # Skip 5
    fi
    if [ $number -eq 8 ]; then
        break      # Stop at 8
    fi
    echo "$number"
done
# Outputs: 1 2 3 4 6 7

Common Mistakes and How to Avoid Them

Always Quote Array Expansions

Unquoted array expansions cause word splitting when elements contain spaces. Always use double quotes:

# Correct
for item in "${array[@]}"; do
    echo "$item"
done

# Incorrect (breaks if any element contains spaces)
for item in ${array[@]}; do
    echo "$item"
done

Use mapfile Instead of Subshell Loops for Reading Files

Avoid for line in $(cat file) — it splits on whitespace and is slower. Use while read or mapfile instead for reliable line-by-line processing.

Check Array Length Before Accessing Elements

Accessing an index that does not exist produces an empty string silently. Check length with ${#array[@]} before assuming elements exist.

Bash arrays and loops are the building blocks that transform simple one-liners into maintainable, reusable scripts. With indexed arrays for sequential data, associative arrays for structured configuration, and loops for repetition, you can automate complex multi-step workflows that would otherwise require manual repetition or more complex scripting languages.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.