跪拜 Guibai
← All articles
Shell · Programming Language

Shell Loops That Actually Work: for, while, until, and When to Use Each

By 柒号华仔 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Getting loops right is the difference between a script that works on your machine and one that survives filenames with spaces, runs on stripped-down containers, and doesn't spin a CPU core to 100%. The while read vs. for-over-find distinction alone prevents a whole class of production bugs.

Summary

Shell scripting's real power sits in its three loop structures: for, while, and until. for iterates over a known list — numbers, files, command output, or array elements — and is the go-to when the iteration count is fixed. while runs as long as a condition holds true, making it the right choice for reading files line-by-line, polling services, or any scenario where the endpoint isn't known upfront. until inverts the logic, looping while a condition is false, which reads more naturally for wait-until-ready patterns.

Practical details separate working scripts from broken ones. Brace expansion ({1..5}) is clean but fails in dash or busybox; seq handles negative steps and zero-padding portably. while read avoids the whitespace-splitting bugs that plague for loops over find output. break and continue control flow, and break n can exit multiple nested levels at once.

Five worked examples — summing 1–100, a multiplication table, service health polling with a timeout, batch file renaming, and CSV statistics — show how these loops compose into real automation. The patterns are small but form the backbone of most ops and data-processing scripts.

Takeaways
for-in iterates over a known list; use it when the number of iterations or the data set is fixed upfront.
while tests a condition before each iteration and is the correct tool for reading files line-by-line, polling, or indefinite retries.
until loops while the condition is false, which reads more naturally than while ! for service-ready checks.
Brace expansion {1..5} is concise but unsupported in dash and busybox; seq handles negative steps, zero-padding, and is portable.
for file in $(find …) breaks on filenames with spaces; while read -r line handles arbitrary characters safely.
break exits the entire loop, continue skips to the next iteration, and break n jumps out of n nested levels.
Always double-quote array expansions like "${arr[@]}" to prevent word-splitting on elements containing spaces.
In infinite loops, a sleep or exit condition is mandatory to avoid pinning the CPU.
Conclusions

Shell's loop constructs map cleanly to intent: for when you know the set, while when you know the condition, until when the exit condition is clearer than the continue condition. Most scripting languages blur these, but shell keeps them distinct, which rewards picking the right one.

The while read pattern is shell's most underappreciated safety mechanism. It sidesteps word-splitting entirely, making it the only reliable way to process arbitrary filenames or CSV rows in production scripts.

Brace expansion's portability trap is a quiet source of breakage when scripts move from interactive bash to container entrypoints running dash or busybox. seq is the safer default for any script that might leave a developer's laptop.

Concepts & terms
IFS (Internal Field Separator)
The shell variable that determines how word-splitting occurs. read uses IFS to split input into fields; for loops use it to split command output. Temporarily changing IFS (e.g., to a comma for CSV) controls parsing, but it must be restored afterward to avoid side effects.
Brace expansion vs. seq
{1..5} is a bash-specific syntax that generates sequences inline. seq is a standalone POSIX utility that outputs sequences to stdout. seq supports negative steps, zero-padding (-w), and works in dash/busybox where brace expansion does not.
Arithmetic expansion $((…))
Shell syntax for integer arithmetic. $((count + 1)) evaluates the expression and substitutes the result. The double-parentheses form ((count++)) performs the operation without substitution, useful as a standalone statement.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗