Loops are the engine of automation. In this lab you'll master every major loop type in Bash: for loops over lists, ranges, globs, and arrays; while and until loops; flow control with break and continue; reading files line-by-line; and nesting loops for matrix operations.
Step 1: for Loop — Iterating a List
The simplest loop: iterate over a space-separated list of values.
💡 Tip: The list items can be any whitespace-separated values. If items contain spaces, quote them individually: for item in "two words" "another item".
Step 2: for Loop — Numeric Range with Brace Expansion
Use {start..end} to generate a numeric sequence without external tools:
📸 Verified Output:
💡 Tip: You can also use a step: {1..10..2} produces 1 3 5 7 9. For dynamic ranges (variables), use seq: for i in $(seq 1 $max).
Step 3: for Loop — Glob Pattern (Files)
Loops over matching filenames — essential for batch file processing:
📸 Verified Output:
💡 Tip: Always check that the glob matched something. If no files match, $f will literally be /tmp/testdir/*.txt. Guard with: shopt -s nullglob so the loop body is skipped when there are no matches.
Step 4: for Loop — Array Iteration
Arrays let you store structured lists and iterate cleanly:
📸 Verified Output:
💡 Tip: Always use "${array[@]}" (double-quoted, @ not *) to iterate arrays safely. Using * joins all elements into one string; @ preserves element boundaries even when elements contain spaces.
Step 5: while Loop
Runs while a condition is true — ideal when the iteration count isn't known in advance:
📸 Verified Output:
💡 Tip:((count++)) is shorthand for count=$((count + 1)). The (( )) form also returns exit status 1 when the result is 0 — be careful with set -e (covered in Lab 04).
Step 6: until Loop
Runs until a condition becomes true — the logical inverse of while:
📸 Verified Output:
💡 Tip:until [ cond ] is equivalent to while [ ! cond ]. Use whichever reads more naturally. until is less common but can make polling logic read cleanly: until server_is_ready; do sleep 1; done.
Step 7: break and continue
break exits the loop immediately; continue skips to the next iteration:
📸 Verified Output:
💡 Tip: In nested loops, break 2 exits two levels at once and continue 2 continues the outer loop. This is cleaner than setting a flag variable.
Step 8: Capstone — Nested Loops and Reading Files
Combine reading a file line-by-line, nested loops, and break/continue in a realistic report generator:
📸 Verified Output:
💡 Tip:IFS=: before read -r user role splits each line on : — a powerful pattern for parsing colon-separated files like /etc/passwd. Always use -r with read to prevent backslash interpretation.
mkdir -p /tmp/testdir
touch /tmp/testdir/file1.txt /tmp/testdir/file2.txt /tmp/testdir/notes.txt
for f in /tmp/testdir/*.txt; do
echo "File: $(basename $f)"
done
File: file1.txt
File: file2.txt
File: notes.txt
colors=("red" "green" "blue")
for color in "${colors[@]}"; do
echo "Color: $color"
done
Color: red
Color: green
Color: blue
count=1
while [ $count -le 5 ]; do
echo "While: $count"
((count++))
done
While: 1
While: 2
While: 3
While: 4
While: 5
n=1
until [ $n -gt 3 ]; do
echo "Until: $n"
((n++))
done
Until: 1
Until: 2
Until: 3
for i in {1..10}; do
[ $i -eq 4 ] && { echo "Skipping 4"; continue; }
[ $i -eq 7 ] && { echo "Breaking at 7"; break; }
echo "i=$i"
done
i=1
i=2
i=3
Skipping 4
i=5
i=6
Breaking at 7
# Setup: create sample data
printf "alice:admin\nbob:user\ncharlie:user\n" > /tmp/users.txt
declare -A PERMS
PERMS[admin]="read write execute"
PERMS[user]="read write"
echo "=== Permission Report ==="
while IFS=: read -r user role; do
echo ""
echo "User: $user Role: $role"
perms=${PERMS[$role]:-none}
for perm in $perms; do
echo " - $perm"
done
done < /tmp/users.txt
echo ""
echo "=== End Report ==="
=== Permission Report ===
User: alice Role: admin
- read
- write
- execute
User: bob Role: user
- read
- write
User: charlie Role: user
- read
- write
=== End Report ===