A small scheduled job I'd half-forgotten about stopped doing its work, and it did it the worst possible way — silently, with no error I'd ever see, because it was running under cron with its output going nowhere. When I finally dug in, the culprit was a single test I'd written carelessly: [ $STATUS = ok ], no quotes. As long as $STATUS came back with a value it was fine. The one time the command feeding it returned nothing, $STATUS expanded to empty, the test collapsed to [ = ok ], and bash choked on a comparison with a missing left-hand side.
That's the whole trap, and it's why every example here quotes its variables. An unquoted variable in [ ] isn't one argument that might be empty — when it's empty it's zero arguments, so the shell sees [ = ok ] and either errors or evaluates something you never meant. Wrap it in quotes and an empty value becomes [ "" = ok ]: still false, but valid, and your branch behaves. The three-branch disk check below is where I rebuilt my intuition for if/elif/else, the comparison operators that actually matter, and the spacing rules bash is unforgiving about — the same small things that, left unquoted, take down a job you'd stopped thinking about. A job dying in silence over a missing pair of quotes is not something I wanted to debug twice.
The three-branch check this all started with
Copy this into disk-if-else.sh. It uses if, elif, and else to classify disk usage into three levels — the same pattern as our disk space warning snippet, with an extra critical branch.
What this does, line by line
THRESHOLD and CRITICAL set the two cutoffs. USAGE reads the current disk percent from df. The first if handles the worst case. elif runs only when the first test failed — still high, but not critical. else covers everything else. fi closes the block — always required.
Building the check yourself
Step 1 — Create the file
Open a terminal and run:
Paste the script above, then press Ctrl+X → Y → Enter to save.
Step 2 — Understand the if/elif/else shape
Every branch follows the same pattern — spaces matter:
| Part | Syntax | Purpose |
|---|---|---|
| if | if [ condition ]; then | First test — runs when true |
| elif | elif [ condition ]; then | Second test — only if previous tests failed |
| else | else | Fallback — runs when no test matched |
| fi | fi | Closes the entire block — do not forget this |
Step 3 — Make it executable
You only need to do this once. It gives the script permission to run.
Step 4 — Run it
You should see one of three messages depending on how full your disk is right now.
Schedule It with Cron
Disk checks only help if they run automatically. Add the script to cron so you catch problems before the drive fills.
Open your crontab
Add one of these lines
Tip: Use crontab.guru
Go to crontab.guru to build and test cron time expressions for free. It explains exactly when your job will run in plain English.
The comparisons you'll actually reach for
String comparison (= and !=)
Use = and != inside [ ] for text. Quote variables so empty values do not break the test:
Check if a file exists (-f)
-f returns true only for regular files. Use -d for directories and -e for either:
Integer comparison (-eq, -gt, -lt)
Numbers inside [ ] need numeric operators, not =:
Bash Comparison Operator Quick Reference
| Type | Operator | Meaning |
|---|---|---|
| Integer | -eq | Equal |
| Integer | -ne | Not equal |
| Integer | -gt | Greater than |
| Integer | -lt | Less than |
| Integer | -ge | Greater than or equal |
| Integer | -le | Less than or equal |
| String | = | Equal |
| String | != | Not equal |
| String | -z | Empty string |
| String | -n | Non-empty string |
| File | -f | Regular file exists |
| File | -d | Directory exists |
| File | -e | File or directory exists |
The bracket traps everyone hits
The trap that actually bit me lives one level below these: an unquoted variable in a test. [ $x = ok ] works until $x is empty, at which point it collapses to [ = ok ] and bash errors on the missing operand. Quoting it — [ "$x" = ok ] — turns an empty value into a harmless empty string instead of a vanished argument. The three below are the ones that break scripts most often.
Forgetting spaces inside [ ]
Bash requires spaces around brackets and operators. if [ "$x" -eq 5 ] works. if ["$x"-eq 5] fails with a syntax error. The [ command needs each piece as a separate argument.
Using = instead of -eq for numbers
Use = for string comparisons. For integers use -eq, -ne, -gt, -lt. Writing if [ "$USAGE" = 80 ] can behave unexpectedly — use -gt for greater-than checks like disk percentages.
Missing fi at the end
Every if block must end with fi (if spelled backwards). Without it, bash reports syntax error: unexpected end of file. Nested ifs need a fi for each level.
Frequently Asked Questions
How do I write an if/else statement in bash?
The basic structure is: if [ condition ]; then ... else ... fi. The spaces around the condition inside [ ] are mandatory — [ "$x" = "y" ] works, ["$x" = "y"] does not.
What is the difference between [ ] and [[ ]] in bash?
[ ] is POSIX-compliant and works in all shells. [[ ]] is a bash extension with additional features: regex matching with =~, no word splitting on unquoted variables, and &&/|| instead of -a/-o. Use [[ ]] in bash-only scripts when you need those features.
How do I compare numbers in a bash if statement?
Use integer comparison operators inside [ ]: -eq (equal), -ne (not equal), -gt (greater than), -lt (less than). Do not use = for numbers — [ 5 = 10 ] does string comparison and can give wrong results.
How do I check if a variable is empty in bash?
Use [ -z "$VAR" ] to test for empty, or [ -n "$VAR" ] for non-empty. Always quote the variable — without quotes, an empty string causes a syntax error in the test.
Why does bash say "command not found" inside an if statement?
The most common cause is a missing then keyword or unquoted variable. Every if line must end with ; then. Check for: missing spaces inside [ ], missing fi at the end, and unquoted variables that contain spaces.