Loops — for, while, and until¶
Overview¶
Fleet checks, log scans, and retry loops are everyday DevOps patterns. Write loops that fail loudly and stop cleanly.
This is Tutorial 6 in Module 6: Loops of the REBASH Academy Shell Scripting for DevOps Engineers series — written for Linux administrators, DevOps engineers, SREs, and platform engineers who automate production hosts with Bash.
Prerequisites¶
- Control Flow — Conditionals
- Bash 4.2+ on Linux (WSL2/VM/cloud)
Learning Objectives¶
By the end of this tutorial, you will be able to:
- Apply the core ideas of “Loops — for, while, and until” in a real ops script
- Use
set -euo pipefailas the production default - Use quoted expansions and clear stderr diagnostics
- Produce meaningful exit codes for automation consumers
- Debug behaviour with
bash -xwhen something fails - Relate this topic to day-to-day Linux admin and DevOps work
Architecture¶
Ops scripts sit between humans/automation and system tools. This topic’s control points are shown below.
Theory¶
What it is¶
Loops repeat a block of commands over a list, a stream of lines, or until a condition changes. Bash offers for (iterate items or a C-style count), while (repeat while a command succeeds), and until (repeat while a command fails). Inside any loop, break leaves early and continue skips to the next iteration. Together these constructs drive host inventories, log scans, readiness probes, and batch file processing — everyday DevOps work.
Why it matters¶
Manual repetition does not scale: checking twenty hosts or pruning a thousand log files by hand invites mistakes. Loops encode that repetition so Continuous Integration (CI), cron, and admin tooling apply the same steps consistently. The cost of a wrong loop is high: an unbounded until can hang a deployment, and an unquoted glob can expand to nothing or to surprising paths. Learning safe patterns — quoted lists, read -r line loops, and retry counters — keeps automation both powerful and predictable.
How it works¶
A for loop walks a fixed list or a glob. Prefer arrays and "$@" when inputs are dynamic; when using globs, guard empty matches:
for host in web01 web02 web03; do
printf 'check %s\n' "$host"
done
for f in /var/log/*.log; do
[[ -e "$f" ]] || continue
wc -l <"$f"
done
A while loop is the classic way to stream files and process output one line at a time:
until condition; do ...; done runs while the condition is false — handy for “wait until ready” probes. Always pair it with a counter or timeout so production jobs cannot loop forever. Keep nested loops shallow; extract the inner body to a function when readability suffers. Use break 2 only when you intentionally leave an outer loop.
Key concepts¶
| Loop | Typical use |
|---|---|
for item in list | Hosts, files, arguments |
while read -r | Line-oriented files and pipelines |
until | Wait-until-ready with a bound |
break / continue | Early exit or skip one iteration |
Arrays / "$@" | Safer than unquoted globs for dynamic input |
Common pitfalls¶
- Writing
for line in $(cat file)and splitting on spaces inside lines - Forgetting
[[ -e "$f" ]]so a non-matching glob becomes a literal string - Infinite
untilreadiness loops without a max-attempts counter - Deep nesting instead of a function, making
breaktargets unclear - Ignoring non-zero status from loop bodies when
set -eis active and a command is allowed to fail
Hands-on Lab¶
Create a workspace for this tutorial.
Focus: for over hosts; while read lines; until ready; break/continue drills
Step 1 – Loops and control¶
cat > loops.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
for h in a b c; do
[[ "$h" == b ]] && continue
echo "host=$h"
done
n=0
while (( n < 3 )); do
n=$((n + 1))
echo "while n=$n"
done
m=0
until (( m >= 2 )); do
m=$((m + 1))
echo "until m=$m"
done
EOF
chmod +x loops.sh
./loops.sh
Final step – Cleanup note¶
Validation¶
- Lab commands run under
~/rebash-shell/lab06/ - You can explain each Theory heading in your own words
- Failure path exits non-zero and prints diagnostics to stderr (where applicable)
- You can relate this topic to a real DevOps or Linux admin task
Code Walkthrough¶
Production Bash for Loops — for, while, and until always combines:
- A clear shebang (
#!/usr/bin/env bash) - Strict mode near the top (
set -euo pipefail) from Module 2 onward - Quoted expansions and explicit tests
- Functions with
localfor reusable behaviour - Documented exit codes and stderr logging
Keep scripts short enough to review in a single merge request. When logic grows (complex JSON APIs, heavy state), hand off to Python and keep Bash as the launcher.
Security Considerations¶
- Treat all external input (args, files, env) as untrusted until validated
- Never log secrets; prefer masked CI variables and secret stores
- Prefer least privilege — do not require root for file-local tasks
- Avoid
evaland unquoted expansions in destructive commands - Validate paths stay under an allow-listed root before
rmor overwrite
Common Mistakes¶
Skipping strict mode
Cron and CI hide failures that an interactive terminal would show. Fix: start with set -euo pipefail from Module 2 onward.
Unquoted path expansions
Spaces and globs rewrite your command line. Fix: always "$path" / "$@".
Assuming interactive PATH
Aliases and fancy PATH entries disappear under schedulers. Fix: set PATH or use absolute paths.
Best Practices¶
- One purpose per script; compose with functions or small binaries
- Log to stderr; reserve stdout for data or RESULT lines
- Idempotent behaviour where scheduling may overlap
- Pair every new script with a failing-path test you actually run
- Run ShellCheck in CI before merging automation
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Works in terminal, fails in cron | PATH / cwd / env | Fingerprint env; set PATH |
unbound variable | set -u | Provide defaults or export vars |
| Pipeline “succeeds” incorrectly | Missing pipefail | set -o pipefail |
[[ unexpected operator | Running under sh/dash | Fix shebang to Bash |
Summary¶
Loops — for, while, and until is a core skill for Linux admins and DevOps engineers automating real hosts and pipelines. Practise the lab until the failure path is as familiar as the happy path, then continue the track.
Interview Questions¶
- How does this topic show up in production Linux administration or CI?
- What failure mode appears if you ignore quoting or strict mode here?
- How would you test this behaviour under a minimal cron-like environment?
- When would you move this logic out of Bash into Python or another tool?
- What exit code contract would you document for teammates?
Sample answer — question 2
Unquoted expansions and missing pipefail create silent or partial failures — especially under cron — that look healthy in monitoring until data is wrong.
Related Tutorials¶
- Shell Scripting for DevOps Engineers – Category Overview
- Control Flow — Conditionals (previous)
- Functions, Parameters, and Locals (next)
- Learning Paths