← Back to Bash Course | Chapter 4: Loops | Lesson 12 of 14

Looping Over Array Elements

You can process every value stored in an array one at a time using a for loop, and optionally get the index alongside each value.

Iterating Values Directly

for val in "${arr[@]}"; do ... done gives you each array element in turn, fully preserved even if an element contains spaces, as long as you quote the expansion. This is the most common and straightforward way to process every item in an array.

Example: Iterating Values Directly

bash
#!/bin/bash
fruits=("apple" "kiwi fruit" "cherry")
for fruit in "${fruits[@]}"; do
    echo "Fruit: $fruit"
done

Iterating Indices with ${!arr[@]}

"${!arr[@]}" expands to the list of indices currently present in the array (not the values), which is useful when you need to know each element's position, especially since Bash arrays can have gaps. You then look up each value with ${arr[idx]} inside the loop.

Example: Iterating Indices with ${!arr[@]}

bash
#!/bin/bash
fruits=("apple" "banana" "cherry")
for idx in "${!fruits[@]}"; do
    echo "Index $idx: ${fruits[idx]}"
done

Why Quoting the Expansion Matters

Leaving ${arr[@]} unquoted lets word splitting break any element containing spaces into multiple separate loop iterations, silently corrupting your data. Quoting it as "${arr[@]}" guarantees each element is treated as exactly one item, regardless of its contents.

Example: Why Quoting the Expansion Matters

bash
#!/bin/bash
items=("first item" "second item")
echo "Unquoted (broken):"
for i in ${items[@]}; do
    echo "  [$i]"
done
echo "Quoted (correct):"
for i in "${items[@]}"; do
    echo "  [$i]"
done

C-Style Loop Over Array Length

A numeric C-style for loop can also walk an array by index, counting from 0 up to (but not including) ${#arr[@]}, the array's element count. This approach is handy when you specifically need to compare or modify neighboring indices, not just read values in order.

Example: C-Style Loop Over Array Length

bash
#!/bin/bash
colors=(red green blue)
for (( i = 0; i < ${#colors[@]}; i++ )); do
    echo "colors[$i] = ${colors[i]}"
done
Common Mistakes
  1. Forgetting to quote ${arr[@]} as "${arr[@]}", which loses the protection for elements that contain spaces and causes them to be split into multiple words.
  2. Using ${arr[*]} when you meant ${arr[@]} inside a loop; [*] joins everything into a single string (subject to IFS), so a for loop over it (quoted) would only see one combined item instead of iterating each element.
  3. Assuming array indices are always sequential when looping with ${!arr[@]}; if elements were removed with unset, gaps can exist, so index-based loops should not assume every number from 0 to length-1 exists.
Chapter Summary
  • for val in "${arr[@]}" iterates over each array element as a separate, fully preserved value.
  • for idx in "${!arr[@]}" iterates over the array's indices (the ! prefix requests indices, not values).
  • Combine both when you need index and value together: loop over "${!arr[@]}" and look up ${arr[idx]}.
  • Always quote "${arr[@]}"/"${!arr[@]}" in loops to keep elements with spaces intact.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.