Build the mental model
An `if`/`elif`/`else`/`fi` block runs different commands depending on whether a test expression succeeds or fails — and in bash, 'success' has a very specific, almost counterintuitive meaning: it's an exit status of exactly 0. That's why any command at all, not just a special 'test' construct, can be used as the condition in an `if`; bash just runs it and checks its exit code. The classic test syntax `[ ]` is actually the `test` command wearing brackets as a disguise, invoked as a normal program with `[` as its literal name (and `]` as a required closing argument), which means it is subject to the exact same word-splitting and globbing dangers as any other command — its arguments need careful, deliberate quoting or an unquoted empty variable can turn `[ $var == value ]` into a syntax error. Bash's own `[[ ]]` extended test is a shell keyword, not a separate program, and that distinction is what lets it sidestep most of that danger: unquoted variables inside it don't get word-split or glob-expanded, and it additionally supports `&&`, `||`, and pattern matching directly inside the brackets instead of requiring `-a`/`-o` or separate bracket pairs. Common test operators include `-f` (regular file exists), `-d` (directory exists), `-z` (string is empty), `-eq` (numeric equality), and `==` (string equality) — and mixing up numeric versus string comparison is one of the most common beginner mistakes, since `-eq` compares two values as integers while `==` compares them character by character as text, and the two are never interchangeable inside `[ ]`.
Connect it to a real scenario
A setup script that needs to check whether a config file exists before reading it, and whether a numeric setting is above some threshold, is a typical place conditionals show up: something like `if [[ -f "$config" ]] && [[ "$timeout" -gt 30 ]]; then` combines a file-existence check with a numeric comparison in one readable line, and using `[[ ]]` means the script won't break even if `$config` happens to contain a space. The lesson's own example walks through the same reasoning step by step: it checks `-f` before trusting a file exists, combines `-d` and `-f` inside a single `[[ ]]` with `&&`, uses `-z` to detect an empty string, and finally contrasts `-lt` (numeric) against `>` inside `[[ ]]` (lexical string comparison) on the values `"9"` and `"10"` — showing exactly how a numeric-looking comparison can silently give a string answer if you reach for the wrong operator.
Try the working example
#!/usr/bin/env bash
# Create a sample file and directory to test against
mkdir -p /tmp/bash-lesson-demo
touch /tmp/bash-lesson-demo/sample.txt
file="/tmp/bash-lesson-demo/sample.txt"
dir="/tmp/bash-lesson-demo"
missing="/tmp/bash-lesson-demo/does-not-exist.txt"
if [ -f "$file" ]; then
echo "$file is a regular file"
fi
if [[ -d "$dir" && -f "$file" ]]; then
echo "Both the directory and file exist"
fi
if [ -f "$missing" ]; then
echo "This should not print"
else
echo "$missing does not exist"
fi
name=""
if [ -z "$name" ]; then
echo "name is empty"
fi
count=10
if [ "$count" -eq 10 ]; then
echo "count numerically equals 10"
fi
# The classic string-vs-numeric pitfall
a="9"
b="10"
if [ "$a" -lt "$b" ]; then
echo "$a is numerically less than $b"
fi
if [[ "$a" > "$b" ]]; then
echo "$a sorts after $b as a STRING (misleading if you meant numbers)"
fi
rm -rf /tmp/bash-lesson-demoRunning this script prints:
/tmp/bash-lesson-demo/sample.txt is a regular file
Both the directory and file exist
/tmp/bash-lesson-demo/does-not-exist.txt does not exist
name is empty
count numerically equals 10
9 is numerically less than 10
9 sorts after 10 as a STRING (misleading if you meant numbers)5-minute try-it
Write a script that checks three things about a path you choose: whether it exists as a directory, whether a specific file inside it exists, and whether a numeric variable representing a retry count is greater than zero — print a clear message for each check using [[ ]].
One important caution
Using [ $var == value ] with an unquoted variable that turns out to be empty or contain spaces, causing a 'unary operator expected' or similar syntax error
Comparing numbers with == instead of -eq (or vice versa comparing strings with -eq), which either fails outright or silently gives the wrong answer
GNU Bash Reference Manual — Bash Conditional Expressions — Bash / Shell Scripting