Loops¶
Iteration patterns in bash: for, while, until, and loop control.
For Loops¶
Basic Syntax¶
Iterating Over Words¶
Iterating Over Files¶
Empty Glob
If no files match, the glob itself becomes the value:
Fix withnullglob: Iterating Over Array¶
Iterating Over Command Output¶
Better - avoid word splitting issues:
C-Style For Loop¶
Range with Brace Expansion¶
With step:
Range with seq¶
for i in $(seq 1 5); do
echo "Number: $i"
done
# With step
for i in $(seq 0 2 10); do
echo "Even: $i"
done
While Loops¶
Basic Syntax¶
Counter Loop¶
Infinite Loop¶
Or:
Reading Lines from File¶
Components explained:
IFS=- Preserve leading/trailing whitespace-r- Don't interpret backslashesline- Variable to store each line
Reading with Process Substitution¶
Reading Multiple Fields¶
# /etc/passwd format: user:x:uid:gid:desc:home:shell
while IFS=: read -r user _ uid gid desc home shell; do
echo "$user has UID $uid"
done < /etc/passwd
Reading from Pipe¶
# Warning: runs in subshell, variables don't persist
echo -e "a\nb\nc" | while read -r line; do
echo "Got: $line"
done
To preserve variables, use process substitution or here string.
Until Loops¶
Run until condition is true (opposite of while):
Waiting for Condition¶
# Wait for file to appear
until [[ -f /tmp/ready ]]; do
echo "Waiting..."
sleep 1
done
echo "File found!"
Loop Control¶
break¶
Exit the loop immediately:
continue¶
Skip to next iteration:
Nested Loop Control¶
Break/continue outer loops with a number:
for i in {1..3}; do
for j in {1..3}; do
if [[ $j -eq 2 ]]; then
break 2 # Break both loops
fi
echo "$i,$j"
done
done
Common Patterns¶
Process All Arguments¶
Find and Process Files¶
# Using find with -exec
find . -name "*.txt" -exec echo "Found: {}" \;
# Using while read (safer for filenames with spaces)
find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do
echo "Found: $file"
done
Retry Until Success¶
max_attempts=5
attempt=1
while [[ $attempt -le $max_attempts ]]; do
if some_command; then
echo "Success on attempt $attempt"
break
fi
echo "Attempt $attempt failed, retrying..."
((attempt++))
sleep 2
done
if [[ $attempt -gt $max_attempts ]]; then
echo "Failed after $max_attempts attempts"
fi
Progress Counter¶
total=100
for ((i=1; i<=total; i++)); do
printf "\rProgress: %d%%" "$((i * 100 / total))"
sleep 0.1
done
echo
Parallel Processing¶
Simple parallel with &:
With controlled parallelism:
max_jobs=4
for file in *.txt; do
while [[ $(jobs -r -p | wc -l) -ge $max_jobs ]]; do
sleep 0.1
done
process_file "$file" &
done
wait
Menu Loop¶
while true; do
echo "1) Option A"
echo "2) Option B"
echo "3) Quit"
read -rp "Choice: " choice
case "$choice" in
1) echo "You chose A" ;;
2) echo "You chose B" ;;
3) break ;;
*) echo "Invalid choice" ;;
esac
done
Accumulator Pattern¶
Loop Performance¶
Avoid External Commands in Loops¶
# Slow - calls external command each iteration
for i in {1..1000}; do
result=$(echo "$i * 2" | bc)
done
# Fast - use bash arithmetic
for i in {1..1000}; do
((result = i * 2))
done
Use While Read for Large Files¶
# Bad - loads entire file into memory
for line in $(cat huge.txt); do
echo "$line"
done
# Good - reads line by line
while IFS= read -r line; do
echo "$line"
done < huge.txt
Select Loop¶
Create simple menus:
PS3="Choose a color: "
select color in "Red" "Green" "Blue" "Quit"; do
case "$color" in
Red|Green|Blue)
echo "You chose: $color"
;;
Quit)
break
;;
*)
echo "Invalid option"
;;
esac
done
Try It¶
-
Basic for loop:
-
File loop:
-
C-style loop:
-
While with counter:
-
Read file:
Summary¶
| Loop Type | Use Case |
|---|---|
for x in list | Known list of items |
for ((i=0;...)) | Counter-based iteration |
while condition | Until condition is false |
until condition | Until condition is true |
select x in list | User menus |
| Control | Effect |
|---|---|
break | Exit loop |
break N | Exit N nested loops |
continue | Skip to next iteration |
continue N | Continue outer loop |
Best practices:
- Quote array expansion:
"${arr[@]}" - Use
while IFS= read -rfor files - Use
-print0/-d ''for filenames with spaces - Avoid external commands inside loops
- Use
waitafter background jobs