Skip to content
DevOps devops shell 5 min read

Arrays

An array is a single variable that holds many values instead of just one. In DevOps work you constantly deal with lists: a list of servers to deploy to, a list of log files to clean up, a list of packages to install. Bash has built-in arrays so you can store these lists and loop over them cleanly, instead of mashing everything into one space-separated string and hoping nothing breaks. This page shows you how to create arrays, read from them, count them, loop over them, and use the more advanced associative arrays (key-value arrays, like a dictionary).

When to use an array

Use an array whenever you have more than one related value that you want to process one at a time. The classic example is a fleet of servers: you have five hostnames, and you want to run the same command on each. An array keeps them together and lets a loop walk through them.

Do NOT use an array when you only ever have a single value (a normal variable is simpler), and avoid them in plain sh scripts. Arrays are a Bash feature, not part of the POSIX (Portable Operating System Interface — the standard that defines the minimal sh shell) standard. They will not work if your script starts with #!/bin/sh. Always use #!/bin/bash when you use arrays.

Declaring an indexed array

An indexed array is the normal kind: each value sits at a numbered position (an index), starting at 0. You create one by listing values inside parentheses.

#!/bin/bash

# Create an indexed array of three server hostnames
servers=("web01" "web02" "db01")

Note there are no commas between items. Bash separates them by spaces. If a value contains a space, wrap it in double quotes so it stays as one item:

fruits=("green apple" "red grape" "banana")

You can also build an array up one item at a time, or append to it later with +=:

servers=()                 # start empty
servers+=("web01")         # add one
servers+=("web02" "db01")  # add several at once

Accessing elements

To read a single element, use its index inside ${ } with square brackets. Remember the first element is index 0, not 1.

servers=("web01" "web02" "db01")
echo "First server: ${servers[0]}"
echo "Third server: ${servers[2]}"

Output:

First server: web01
Third server: db01

Always wrap array access in ${ } braces, like ${servers[0]}. If you write $servers[0] without braces, Bash reads it as the variable $servers (which is just the first element) followed by the literal text [0]. That bug is silent and confusing, so use braces every time.

To grab a negative index (counting from the end), Bash supports ${servers[-1]} for the last element:

echo "Last server: ${servers[-1]}"

Output:

Last server: db01

Getting all elements with ${arr[@]}

To work with the whole array at once, use [@] instead of a number. The special form "${servers[@]}" expands to every element, and the double quotes keep each element separate even if it contains spaces. This is the form you want almost all the time.

servers=("web01" "web02" "db01")
echo "All servers: ${servers[@]}"

Output:

All servers: web01 web02 db01

There is a close cousin, ${servers[*]}, which joins everything into one string. The difference only matters inside quotes:

ExpansionWhat it doesWhen to use
"${arr[@]}"Each element stays a separate wordLooping, passing to commands — the safe default
"${arr[*]}"All elements joined into one stringBuilding a single display string
${arr[@]} (unquoted)Splits on spaces inside elements tooAlmost never — it breaks values with spaces

Counting elements with ${#arr[@]}

To find out how many items an array holds, put a # in front. The ${#servers[@]} form gives the count (the length).

servers=("web01" "web02" "db01")
echo "We manage ${#servers[@]} servers."

Output:

We manage 3 servers.

Note: ${#servers} without the [@] gives the character length of the first element, which is rarely what you want. Always include [@] to count items.

Looping over an array

The most common thing you do with an array is loop over it. The for loop pairs perfectly with "${arr[@]}". Here is a realistic script that “pings” (sends a small network test packet to check if a host is reachable) each server in a fleet.

#!/bin/bash

# Build an array of servers to check
servers=("web01.example.com" "web02.example.com" "db01.example.com")

echo "Checking ${#servers[@]} servers..."

for server in "${servers[@]}"; do
  if ping -c 1 -W 2 "$server" > /dev/null 2>&1; then
    echo "OK   - $server is reachable"
  else
    echo "FAIL - $server is down"
  fi
done

Output:

Checking 3 servers...
OK   - web01.example.com is reachable
OK   - web02.example.com is reachable
FAIL - db01.example.com is down

If you also need the index (the position number) while looping, loop over the indices using "${!servers[@]}" (the ! gives you the keys, not the values):

servers=("web01" "web02" "db01")
for i in "${!servers[@]}"; do
  echo "Server #$i is ${servers[$i]}"
done

Output:

Server #0 is web01
Server #1 is web02
Server #2 is db01

Associative arrays (key-value)

An associative array uses text keys instead of numbers, like a dictionary or a map in other languages. You must declare it first with declare -A (the capital A is required; lowercase -a means a normal indexed array). This is handy for storing settings or mapping a server name to its role.

#!/bin/bash

declare -A roles
roles["web01"]="frontend"
roles["web02"]="frontend"
roles["db01"]="database"

# Look up one value by its key
echo "web01 runs the ${roles[web01]} tier"

# Loop over keys and values
for host in "${!roles[@]}"; do
  echo "$host -> ${roles[$host]}"
done

Output:

web01 runs the frontend tier
web02 -> frontend
db01 -> database
web01 -> frontend

Associative arrays need Bash 4.0 or newer. Ubuntu 22.04 and 24.04 LTS ship Bash 5, so you are fine. But macOS still ships the ancient Bash 3.2, so a script using declare -A will fail there. Stick to Linux for these.

The order of an associative array is not guaranteed, so do not rely on keys coming back in the order you added them.

Best practices

  • Always quote array expansions as "${arr[@]}" so values with spaces survive intact.
  • Use ${#arr[@]} to get the count and never assume a fixed size; let the array drive the loop.
  • Start scripts with #!/bin/bash, never #!/bin/sh, when you use arrays.
  • Build arrays with += when collecting items in a loop, rather than concatenating strings.
  • Declare associative arrays explicitly with declare -A before assigning keys, or Bash treats them as plain indexed arrays.
  • Use "${!arr[@]}" when you need indices or keys, not just values.
  • Keep a server list in one array near the top of the script so it is easy to edit later.
Last updated June 15, 2026
Was this helpful?