Reading — step 1 of 5
Learn
if and case
Bash conditionals hide a beautiful secret: there is no boolean type — there are exit statuses. if doesn't test a condition; it runs a command and branches on whether that command succeeded. Once you see it, half of bash's odd syntax snaps into focus.
if runs commands
if grep -q "error" logfile.txt; then
echo "found errors"
fi
grep exits 0 when it finds a match (success), non-zero otherwise — and if branches on exactly that. Any command can be the condition. So what's the square-bracket thing everyone writes?
if [[ "$n" -gt 10 ]]; then
echo "big"
fi
[[ … ]] is itself a test construct that succeeds or fails — purpose-built for comparisons. (Its ancestor [ is literally a program — /usr/bin/[ — which explains the mandatory spaces around it. Use modern [[ ]] in bash scripts: safer parsing, more features; recognize [ ] in old scripts.)
The two comparison alphabets
Bash's original sin: numbers and strings compare with different operators.
[[ "$a" -eq "$b" ]] # numeric: -eq -ne -lt -le -gt -ge
[[ "$s" == "yes" ]] # string: == != < >
[[ -z "$s" ]] # string is empty
[[ -n "$s" ]] # string is non-empty
Mixing them "works" just often enough to be dangerous: [[ "10" < "9" ]] is TRUE (string comparison is alphabetical, and "1" sorts before "9"). Numbers get dash-letters, strings get symbols — drill it now. Files get their own test flags, everywhere in real scripts: -f file exists-and-is-a-file, -d is-a-directory, -r readable, -x executable.
Combine with && / || inside [[ ]], and ! negates. if/elif/else/fi closes with fi — bash blocks end in reversed keywords (fi, esac, done), a 1970s Algol homage you'll stop noticing within a week.
case: pattern matching for text
When one variable routes to many branches, case beats an elif ladder — and it matches globs, not just literals:
case "$file" in
*.txt) echo "text" ;;
*.jpg|*.png) echo "image" ;;
backup_*) echo "backup" ;;
*) echo "unknown" ;;
esac
Each pattern ends with ), each branch ends with ;;, *) is the default, esac closes. case is the tool for argument parsing and file-type routing — you'll meet it again in the getopts lesson.
Your exercise: FizzBuzz for one number
Read n; multiples of 3 → Fizz, 5 → Buzz, both → FizzBuzz, else the number. Bash edition:
read n
if (( n % 15 == 0 )); then
echo "FizzBuzz"
elif (( n % 3 == 0 )); then
echo "Fizz"
elif (( n % 5 == 0 )); then
echo "Buzz"
else
echo "$n"
fi
Note the third bracket flavor: (( )) — arithmetic conditions, where C-style operators (%, ==, <) work on numbers directly, no dash-letters needed. Rule of thumb: (( )) for math tests, [[ ]] for strings and files. And the eternal FizzBuzz law, fourth language running: most specific case first — 15 before 3 before 5. Some lessons are the same in every language; that's why they're fundamentals.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…