if and the [[ ]] Test
Run backup.sh with no argument and it happily archives an empty path. Run it with a typo and tar fails halfway. A careful script checks its input first and refuses politely. That needs a way to choose between actions.
The rule
ifruns a command; status zero takes thethenbranch.
if [[ $# -lt 1 ]]; then
echo "Usage: $0 SOURCE [NAME]" >&2
exit 2
fi
src="$1"
if [[ ! -d "$src" ]]; then
echo "Not a folder: $src" >&2
exit 1
elif [[ ! -r "$src" ]]; then
echo "Cannot read: $src" >&2
exit 1
else
echo "Backing up $src"
fi(>&2 sends a message to standard error, so it does not mix with real output.)
if does not test "true or false" in the abstract. It runs a command and looks at its exit status. [[ ... ]] is simply a command whose status is 0 when the test inside holds. So any command works:
if tar -czf "$archive" "$src"; then echo "Saved"; fi
if grep -q ERROR log.txt; then echo "Errors found"; fiThe tests you will use most inside [[ ]]:
| Kind | Operators |
|---|---|
| Strings | == != equal, not equal; -z empty; -n not empty |
| Numbers | -eq -ne -lt -le -gt -ge |
| Files | -e exists, -f regular file, -d directory, -r -w -x readable, writable, executable, -s not empty |
| Negation | ! in front of a test |
For numbers you can also use arithmetic: if (( count > 10 )); then. Older scripts use single brackets [ ... ], which work in any POSIX shell but are fussier: variables must be quoted inside them.
The shortcut
Match the operator family to the data: letters for numbers in [[ ]] (-lt, -eq), symbols for text (==, <), dashes plus a letter for files (-d). A symbol like > inside [[ ]] compares dictionary order, not size.
Which family?
>is a symbol, so this is a text comparison.
The other classic mistake is missing spaces. [[ is a word of its own, so [[$x == y]] fails with a "command not found" error.
Drills
Answer fast — trust the rule.
Does [[ 10 > 9 ]] succeed?
Which test is true when $src is an existing directory?
When does if grep -q ERROR log.txt; then ... run its then branch?
What happens with if [[$x == y]]; then?
Which test is true when the variable name is empty?
Remember
ifruns a command; status zero takes thethenbranch.- Match the family:
-ltfor numbers,==and<for text,-dfor files. - Trap:
>in[[ ]]is dictionary order; spaces around[[and]]are required.
