| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | bash 5.2.26-6.el10 |
| Applies to | Linux distributions with Bash installed |
| Privilege | Normal user; systemctl examples need a running service on the host |
| Scope | Bash if, elif, and else syntax, exit-status semantics, [ ] / [[ ]] / (( )) as brief bridges, combining conditions, command-based tests, nested if statements, and common errors. Detailed string, numeric, and file test operators are covered in sibling guides. |
| Related guides | Bash shell script tutorial Shell scripting course hub |
In Bash, if runs a command or condition and chooses a branch based on whether it succeeds or fails. An exit status of 0 means success, while any nonzero status means failure. You do not need a special Boolean type — a plain command such as grep -q or command -v is enough.
The examples below show common uses of if, including dependency checks, file tests, environment modes, and retry counters. For the full operator lists behind [ ] and [[ ]], see the dedicated comparison and file-test guides linked below.
Bash if Statement Syntax
A simple if runs one branch when the condition succeeds:
if CONDITION; then
commands
fiCONDITION can be a test such as [ "$count" -ge 3 ], a Bash conditional such as [[ "$mode" = prod ]], or any command that returns success or failure.
Add elif and else when you need more paths:
if CONDITION; then
commands
elif CONDITION; then
commands
else
commands
fithen and fi are required keywords. Bash uses elif, not else if. Only one if / fi pair wraps the whole chain, no matter how many elif lines you add. else does not have its own condition; it runs only when all previous if and elif conditions fail.
Bash if on One Line
Semicolons separate commands that would normally sit on separate lines:
mode=prod
if [ "$mode" = prod ]; then echo 'production'; fiproductionReserve one-liners for quick checks at the shell prompt.
How Bash if Conditions Work
if runs the command or condition after it and checks the resulting exit status. See Bash exit codes for how $? records that status.
These all work as conditions:
grep -q pattern file— success when a match existscommand -v jq— success whenjqis onPATHsystemctl is-active --quiet "$service"— success when the unit is active[[ "$var" = prod ]]— success when the conditional returns0
A failed command (nonzero exit) skips the then block and moves to the next elif or else.
Prefer testing the command inside if instead of reading $? afterward:
printf 'mode=production\n' > app.conf
if grep -q '^mode=' app.conf; then echo 'found'; fifoundThis also works, but testing the command directly is clearer and avoids the risk of $? being changed if another command is added before the if:
grep -q '^mode=' app.conf
if [ "$?" -eq 0 ]; then echo 'found'; fifoundPrefer the first form.
Simple Bash if Statement
Run a numeric comparison when you only need one branch. Inside [ ], -ge means greater than or equal to:
count=5
threshold=3
if [ "$count" -ge "$threshold" ]; then
echo "count is at least $threshold"
ficount is at least 3[ … ] is the test command — quote variables inside it.
Check a Variable with if
Compare a string variable when the value selects behavior:
environment='production'
if [[ "$environment" = production ]]; then
echo 'production settings enabled'
fiproduction settings enabledBash if else Statement
Add else for the path that runs when the condition fails. Change ./app.conf to the file you want to test. -f is true when the path exists and is a regular file:
config='./app.conf'
touch "$config"
if [ -f "$config" ]; then
echo 'config found'
else
echo 'config missing'
ficonfig foundSee check if a file exists in Bash for other -f / -d tests.
Bash if elif else Statement
Use elif to classify more than two outcomes. Bash checks conditions from top to bottom and runs the first then block whose test succeeds; later branches are skipped.
Pick the mode from an environment variable:
APP_MODE=prod
if [ "$APP_MODE" = prod ]; then
echo 'production mode'
elif [ "$APP_MODE" = dev ]; then
echo 'dev mode'
else
echo 'unknown mode'
fiproduction modeQuote variable expansions inside [ … ] so empty values or spaces do not change how test receives its arguments.
Put stricter tests before broader ones:
a=10
b=10
if [ "$a" -eq "$b" ]; then
echo 'equal'
elif [ "$a" -ge "$b" ]; then
echo 'greater-or-equal'
fiequalWhen a and b are equal, both -eq and -ge are true. Bash stops at the first true branch, so -eq must come first if you want equality handled separately.
Classify a retry counter by threshold:
attempts=3
if [ "$attempts" -eq 0 ]; then
echo 'not started'
elif [ "$attempts" -lt 3 ]; then
echo 'retrying'
else
echo 'give up'
figive up3 is not less than 3, so the else branch runs.
Bash Conditions: [ ], [[ ]], and (( ))
Bash commonly uses three forms for conditions inside if:
| Form | Typical use |
|---|---|
[ … ] |
POSIX test; useful when portability to other shells matters |
[[ … ]] |
Bash conditional syntax; supports pattern matching and combining conditions more conveniently. It also avoids normal word splitting inside the expression |
(( … )) |
Bash arithmetic conditions using C-style integer expressions |
The three forms differ in portability and parsing — Bash test vs double brackets compares [ ], [[ ]], and (( )) side by side. In Bash-only scripts, [[ … ]] is generally easier for string and file conditions; use [ … ] when Bash vs sh portability matters. String operators (=, ==, -z, -n) are in compare strings in Bash; integer operators (-eq, -lt, -ge) are in compare numbers in Bash.
Inside (( … )), Bash treats the contents as integer arithmetic, so you can use operators such as >, <, >=, and == instead of -gt, -lt, and -ge:
n=7
if (( n > 0 )); then
echo 'positive'
fipositiven is greater than zero.
Combine Bash if Conditions
With &&, Bash stops as soon as one condition fails. With ||, Bash stops as soon as one condition succeeds.
AND with &&
With [ … ], && connects two separate test commands:
n=3
if [ "$n" -ge 1 ] && [ "$n" -le 5 ]; then
echo 'in range'
fiin rangeInside [[ … ]], && is part of the conditional expression itself:
if [[ "$n" -ge 1 && "$n" -le 5 ]]; then
echo 'in range'
fiin rangeBoth styles print the same line.
OR with ||
Use || when either condition should pass:
day='Saturday'
if [[ "$day" = Saturday || "$day" = Sunday ]]; then
echo 'weekend'
fiweekendNOT with !
Prefix ! to negate a command:
printf 'mode=production\n' > app.conf
if ! grep -q '^missing=' app.conf; then echo 'key absent'; fikey absentThe pattern was not found, so the negated test succeeds.
Use Commands Directly in if
Because if branches on exit status, you can often test a command directly instead of comparing its output or $? afterward.
command -v succeeds when Bash can find an executable on PATH — the which command contrasts which, command -v, and type -a when you verify what an if command -v test will resolve. For example:
if command -v jq >/dev/null 2>&1; then
echo 'jq is installed'
else
echo 'jq missing'
fijq is installedYour output depends on whether jq is installed.
Search a config file without printing matches:
printf 'mode=production\n' > app.conf
if grep -q '^mode=' app.conf; then
echo 'mode key present'
fimode key presentSee grep command in Linux for flags and patterns.
Check whether a service unit is active with systemctl. Replace sshd with a unit available on your system; Debian and Ubuntu commonly use ssh:
service=sshd
if systemctl is-active --quiet "$service"; then
echo "$service is active"
else
echo "$service is not active"
fisshd is activeYour output depends on whether that service unit exists and is running on your system.
Nested if Statements
You can nest if blocks inside then or else:
file='app.conf'
touch "$file"
if [[ -f "$file" ]]; then
if [[ -r "$file" ]]; then
echo 'config exists and is readable'
fi
ficonfig exists and is readableWhen conditions combine cleanly, && may avoid unnecessary nesting:
if [[ -f "$file" && -r "$file" ]]; then
echo 'config exists and is readable'
ficonfig exists and is readableOne combined condition replaces the nested blocks.
Bash if vs case
if / elif fits comparisons and command status checks. When one variable must match many fixed strings — especially $1 in a script — Bash case statement is often clearer:
case "$1" in
start|stop|restart) ...
status) ...
*) ...
esacUse if when branches depend on numeric ranges, file tests, or command success. Use case when you are matching discrete string patterns.
Common Bash if Errors
| Problem | Cause | Fix |
|---|---|---|
syntax error near unexpected token |
Missing then or fi |
Every if needs then … fi; elif does not add a second fi |
syntax error near unexpected token elif |
Wrote else if |
Bash uses elif, not else if |
[ : missing ] or too many arguments |
Missing spaces inside [ ] |
Write [ "$a" = "$b" ] — spaces around [, ], and operators |
| Wrong branch for numbers | String > instead of -gt |
Use -eq, -lt, -ge in [ ], or (( )) for arithmetic |
| Unquoted empty or spaced variable causes test errors | Expansion changes the number of arguments passed to [ ] |
Quote expansions: "$var" |
$? shows unexpected value |
Ran another command before reading $? |
Test the command directly in if, or save $? immediately |
Later elif never runs |
Broader test listed first | Put stricter tests before looser ones |
Summary
Bash if, elif, and else branch on command exit status — 0 is true, nonzero is false. You can test plain commands (grep -q, command -v, systemctl is-active) or wrap comparisons in [ ], [[ ]], or (( )). Quote variables, put stricter elif tests before broader ones, and reach for dedicated guides when you need every string, numeric, or file operator spelled out.
When a command already reports success or failure through its exit status, use that command directly in if instead of checking $? afterward. When a variable must match many fixed tokens, consider case instead of a long elif chain.
References
- GNU Bash manual — Conditional Constructs
- GNU Bash manual — Bash Conditional Expressions
- POSIX
testutility
Frequently Asked Questions
Does Bash if require [ ]?
No. if can run any command or command list. [ … ] uses the test builtin, while [[ … ]] is Bash conditional syntax; both return a status that if can branch on. You can also write if grep -q pattern file; then or if command -v tool; then with no brackets.
What does elif mean?
elif is short for “else if.” Bash evaluates each condition in order and runs the first then block whose test succeeds. It is not written as two words (else if).
How do I combine two conditions?
Use && for AND and || for OR between commands or tests: [ "$a" -ge 1 ] && [ "$a" -le 5 ], or [[ "$a" -ge 1 && "$a" -le 5 ]]. Prefix ! to negate a test.
Can I write Bash if on one line?
Yes. Put then and the body on one line with semicolons: if [ "$mode" = prod ]; then echo 'production'; fi. This is fine at the prompt; in scripts, the multi-line form is easier to read.
if vs case — which should I use?
Use if for numeric ranges, file tests, command success, and mixed logic. Use case when one variable must match a set of fixed string patterns, especially script arguments like start or stop.

