← Back to Bash Course | Chapter 6: Arrays | Lesson 7 of 10

Iterating Arrays

There are a few different ways to loop over an array depending on whether you need just the values, just the positions, or both together.

Iterating Just the Values

Looping directly over "${arr[@]}" is the simplest option when you only need each value and don't care about its position in the array. This works identically for both dense and sparse arrays.

Example: Iterating Just the Values

bash
#!/bin/bash
tasks=("write code" "run tests" "deploy")
for task in "${tasks[@]}"; do
    echo "Task: $task"
done

Iterating Indices for Sparse Arrays

"${!arr[@]}" returns only the indices that actually have a value assigned, which correctly handles sparse arrays where some numeric positions were skipped. A plain for (( i=0; i<len; i++ )) loop would not know to skip missing indices.

Example: Iterating Indices for Sparse Arrays

bash
#!/bin/bash
declare -a sparse
sparse[0]="first"
sparse[3]="fourth"
for idx in "${!sparse[@]}"; do
    echo "Index $idx has value: ${sparse[idx]}"
done

Iterating Index and Value Together

Looping over "${!arr[@]}" and then looking up ${arr[idx]} inside the loop body gives you both the position and the value on each pass. This pattern works correctly regardless of whether the array is dense or sparse.

Example: Iterating Index and Value Together

bash
#!/bin/bash
players=(Alice Bob Carol)
for i in "${!players[@]}"; do
    echo "Player #$i: ${players[i]}"
done

Iterating an Associative Array by Key

For associative arrays, iterating over "${!arr[@]}" gives you the string keys (since there's no meaningful numeric position), and you look up each value with ${arr[key]}. This is the only correct general-purpose way to walk an associative array's contents.

Example: Iterating an Associative Array by Key

bash
#!/bin/bash
declare -A prices
prices["coffee"]=4
prices["tea"]=3
for item in "${!prices[@]}"; do
    echo "$item costs \$${prices[$item]}"
done
Common Mistakes
  1. Forgetting the ! prefix means 'give me the indices', so ${!arr[@]} and ${arr[@]} look similar but return completely different things (positions vs. values).
  2. Assuming a for loop over ${!arr[@]} will always produce a contiguous range like 0,1,2...; if the array is sparse, only the indices that actually exist are returned.
  3. Using a C-style for (( i=0; i<${#arr[@]}; i++ )) loop on a sparse array and assuming every i corresponds to a real element; some of those indices might not exist, silently producing empty values.
Chapter Summary
  • for val in "${arr[@]}" iterates values directly, in index order.
  • for idx in "${!arr[@]}" iterates the actual existing indices/keys, correctly skipping gaps in sparse arrays.
  • Combine the two (loop over indices, then look up ${arr[idx]}) whenever you need position and value together.
  • For associative arrays, only the ${!arr[@]} (keys) and lookup-by-key approach works -- there's no meaningful 'numeric position' to iterate by.

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.