<aside> 🔱
Module 5 — Conditionals: if, test, and case. Scripts that decide — check a file exists before deleting, check a service is up before deploying. This is where scripts stop being command lists and start being programs.
🧠 concept → 🧩 analogy → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (hidden)
</aside>
<aside> 📋
Before you start. You need Modules 1–4, and especially Module 3: if is built directly on exit codes, and this module makes no sense without them. Also load-bearing: Module 2's quoting reflex (one exercise here shows exactly what it prevents) and Module 4's >&2. Tools: nothing new. Keep ~/bash-course with users.txt.
</aside>
<aside> 📖
Official docs: Bash manual — Conditional Constructs
</aside>
Here is the fact that makes bash conditionals click, and that most tutorials bury: if does not evaluate a "condition." It runs a command and reads its exit status. Verdict 0 → the then block runs; any other verdict → it doesn't. The full grammar:
if some-command; then
commands-for-success
elif other-command; then # optional, as many as you like
commands-if-THAT-succeeded
else # optional
commands-if-everything-failed
fi # "if" backwards — closes the block
Any command can stand guard. if grep -q bob users.txt — grep's verdict decides. if ./preflight.sh — your own script's exit code (Module 3 C2) decides; that is why truthful verdicts mattered. And ! in front of a command flips its verdict: if ! grep -q zoe users.txt reads "if zoe is not in the file." Compare this with Module 3's &&: same verdict-reading machinery, but if binds its else to the one command you name — which is exactly the fix for the a && b || c trap.
<aside> 🧩
Real-world analogy — the bouncer. if posts a bouncer at a door: the bouncer runs one check ("on the list?") and the answer — yes or no, nothing in between — decides which corridor you walk down. The check can be trivial or elaborate (a whole preflight script), but it must compress to one verdict, because doors only open or close.
Where the analogy stops working. A bouncer evaluates you; if evaluates nothing — it delegates entirely. There is no "condition language" hiding inside if; the [ ... ] you have seen in other people's scripts is not if-syntax, it is a separate command with its own verdict, and Part B introduces it as exactly that. Grasping this dissolves half of bash's apparent weirdness in advance.
</aside>
🧪 Exercise 5.1 — commands as conditions
cd ~/bash-course
if grep -q bob users.txt; then
echo "bob is on the list"
fi
if ! grep -q zoe users.txt; then
echo "zoe is not"
fi
if grep -q zoe users.txt; then
echo "zoe found"
else
echo "no zoe; adding a placeholder note" >&2
fi
[ is a command. Its name is one square bracket. Really.<aside> 📖
Official docs: Bash manual — Bash Conditional Expressions · test(1) — man7.org
</aside>
if reads verdicts, but plenty of questions have no ready-made command: is this string empty? is that a directory? is x greater than 3? The answer is a command whose entire purpose is turning small questions into exit codes: test. test -f /etc/hosts exits 0 if that file exists and is a regular file; 1 if not. And test has a famous disguise: the command [ — same program, but when invoked by its bracket name it demands a matching ] as its final argument, purely so your code reads like syntax:
if [ -f /etc/hosts ]; then echo "found"; fi