Bash if, elif, else with Examples

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
Short on time?Beta Get the gist of this 10-minute read in seconds, then ask follow-up questions

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:

text
if CONDITION; then
  commands
fi

CONDITION 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:

text
if CONDITION; then
  commands
elif CONDITION; then
  commands
else
  commands
fi

then 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:

bash
mode=prod
if [ "$mode" = prod ]; then echo 'production'; fi
output
production

Reserve 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 exists
  • command -v jq — success when jq is on PATH
  • systemctl is-active --quiet "$service" — success when the unit is active
  • [[ "$var" = prod ]] — success when the conditional returns 0

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:

bash
printf 'mode=production\n' > app.conf
if grep -q '^mode=' app.conf; then echo 'found'; fi
output
found

This also works, but testing the command directly is clearer and avoids the risk of $? being changed if another command is added before the if:

bash
grep -q '^mode=' app.conf
if [ "$?" -eq 0 ]; then echo 'found'; fi
output
found

Prefer 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:

bash
count=5
threshold=3

if [ "$count" -ge "$threshold" ]; then
  echo "count is at least $threshold"
fi
output
count 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:

bash
environment='production'

if [[ "$environment" = production ]]; then
  echo 'production settings enabled'
fi
output
production settings enabled

Bash 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:

bash
config='./app.conf'
touch "$config"

if [ -f "$config" ]; then
  echo 'config found'
else
  echo 'config missing'
fi
output
config found

See 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:

bash
APP_MODE=prod

if [ "$APP_MODE" = prod ]; then
  echo 'production mode'
elif [ "$APP_MODE" = dev ]; then
  echo 'dev mode'
else
  echo 'unknown mode'
fi
output
production mode

Quote variable expansions inside [ … ] so empty values or spaces do not change how test receives its arguments.

Put stricter tests before broader ones:

bash
a=10
b=10

if [ "$a" -eq "$b" ]; then
  echo 'equal'
elif [ "$a" -ge "$b" ]; then
  echo 'greater-or-equal'
fi
output
equal

When 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:

bash
attempts=3

if [ "$attempts" -eq 0 ]; then
  echo 'not started'
elif [ "$attempts" -lt 3 ]; then
  echo 'retrying'
else
  echo 'give up'
fi
output
give up

3 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:

bash
n=7

if (( n > 0 )); then
  echo 'positive'
fi
output
positive

n 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:

bash
n=3

if [ "$n" -ge 1 ] && [ "$n" -le 5 ]; then
  echo 'in range'
fi
output
in range

Inside [[ … ]], && is part of the conditional expression itself:

bash
if [[ "$n" -ge 1 && "$n" -le 5 ]]; then
  echo 'in range'
fi
output
in range

Both styles print the same line.

OR with ||

Use || when either condition should pass:

bash
day='Saturday'

if [[ "$day" = Saturday || "$day" = Sunday ]]; then
  echo 'weekend'
fi
output
weekend

NOT with !

Prefix ! to negate a command:

bash
printf 'mode=production\n' > app.conf

if ! grep -q '^missing=' app.conf; then echo 'key absent'; fi
output
key absent

The 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:

bash
if command -v jq >/dev/null 2>&1; then
  echo 'jq is installed'
else
  echo 'jq missing'
fi
output
jq is installed

Your output depends on whether jq is installed.

Search a config file without printing matches:

bash
printf 'mode=production\n' > app.conf

if grep -q '^mode=' app.conf; then
  echo 'mode key present'
fi
output
mode key present

See 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:

bash
service=sshd

if systemctl is-active --quiet "$service"; then
  echo "$service is active"
else
  echo "$service is not active"
fi
output
sshd is active

Your 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:

bash
file='app.conf'
touch "$file"

if [[ -f "$file" ]]; then
  if [[ -r "$file" ]]; then
    echo 'config exists and is readable'
  fi
fi
output
config exists and is readable

When conditions combine cleanly, && may avoid unnecessary nesting:

bash
if [[ -f "$file" && -r "$file" ]]; then
  echo 'config exists and is readable'
fi
output
config exists and is readable

One 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:

text
case "$1" in
  start|stop|restart) ...
  status) ...
  *) ...
esac

Use 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


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.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)