Using test and Conditional Expressions (Part 11 / 34)







Bash if Statement: Complete Guide with Examples | LinuxTeck


If you have ever wanted your Linux scripts to make decisions on their own, you are in the right place. The bash if statement is a fundamental building block that allows shell scripts to test conditions and decide what action to take next.

This bash if statement complete guide with examples covers everything from basic syntax to real-world sysadmin use cases, helping you write scripts that are actually useful and reliable in production environments.

Why This Guide Exists

Most articles about bash conditional expressions stop at the basic syntax. They skip the parts that actually bite you on the job:

  • The difference between [ ], [[ ]], and (( )) and when each one breaks
  • Errors like "unary operator expected" that nobody explains clearly
  • Real scripts for Ubuntu, Rocky Linux, and RHEL environments
  • What happens when you mix set -e with if statements

By the end of this article you will know not just how bash if statements work but also why they fail and how to fix them fast.

Before writing conditional logic, you should already have a working Bash environment set up. If you are completely new to Bash scripting, it is a good idea to first learn the basics of what Bash scripting is and how to get started, then come back to this guide afterward.

#01

The Three Syntax Forms: [ ], [[ ]], and (( ))

One thing that often confuses both beginners and even some intermediate users is that Bash provides three different ways to write conditions. Each method behaves a little differently, and choosing the wrong one can sometimes lead to silent bugs or unexpected errors. The comparison below gives you a side-by-side look at these conditional methods before you start writing any actual conditional code.

Syntax Name Works in sh? String Glob? Regex =~? Best For
[ ] POSIX test YES NO NO Portable scripts, basic file/string checks
[[ ]] Bash keyword NO YES YES Most Bash scripts, pattern matching, safe quoting
(( )) Arithmetic eval NO NO NO Integer math comparisons only

Pro-Tip: Avoid Silent Bugs:

Always start your Bash scripts with #!/bin/bash.

Crucial Rule: Remember that [ ] and [[ ]] require operators like -eq, -gt, or -lt for numbers. If you use (( )), you must use math symbols like ==, >, or <. Mixing these is the #1 cause of script failure for beginners!

Senior Developer Best Practices:

  • Strict Validation: Never trust user input. Always check if a variable contains a number before comparing it.
  • Graceful Exits: Always use exit 1 after an error message so the system knows the script failed.
  • Better Scoping: Use [[ ]] instead of [ ] for most Bash tasks—it's safer and handles empty variables better.

Now let us look at the basic if statement structure using all three forms:

bash
LinuxTeck.com
#!/bin/bash
# Form 1: POSIX single bracket — portable
if [ "$name" = "admin" ]; then
echo "Welcome, admin"
fi

# Form 2: Bash double bracket — safer, supports glob and regex
if [[ "$name" == admin* ]]; then
echo "Looks like an admin account"
fi

# Form 3: Arithmetic double parenthesis — numbers only
if (( count > 10 )); then
echo "Count exceeds 10"
fi

#02

Bash Conditional Test Operators: Complete Reference

Bash ships with a large set of test operators split across four categories. Most articles dump them in a single wall-of-text table. Below each category gets its own table with a ready-to-run script so you can test each one on your own system.

Integer (Number) Operators

Operator Meaning Example
-eq Equal to [ $a -eq $b ]
-ne Not equal to [ $a -ne $b ]
-lt Less than [ $a -lt 10 ]
-le Less than or equal [ $a -le 10 ]
-gt Greater than [ $a -gt 5 ]
-ge Greater than or equal [ $a -ge 5 ]
bash
LinuxTeck.com
#!/bin/bash
# Integer operator examples
a=15
b=10

if [ $a -gt $b ]; then
echo "$a is greater than $b"
fi

if (( a - b == 5 )); then
echo "Difference is exactly 5"
fi

if [ $a -ne 20 ]; then
echo "a is not 20"
fi

OUTPUT
15 is greater than 10
Difference is exactly 5
a is not 20

String Operators

Operator Meaning Example
= or == Strings are equal [ "$a" = "$b" ]
!= Strings are not equal [ "$a" != "$b" ]
-z String is empty (zero length) [ -z "$var" ]
-n String is not empty [ -n "$var" ]
=~ Regex match (bash only) [[ "$var" =~ ^[0-9]+$ ]]

File and Path Operators

Operator True If
-f file File exists and is a regular file
-d dir Directory exists
-e path File or directory exists
-r file File is readable
-w file File is writable
-x file File is executable
-s file File exists and is not empty
-L file File is a symbolic link

Miscellaneous / Boolean Operators

Operator Meaning
! NOT — negates the condition
-a or && AND — both conditions must be true
-o or || OR — at least one condition must be true

Note

Inside [ ] use -a and -o for AND and OR. Inside [[ ]] use && and || instead. Mixing them up causes "unexpected token" errors. For a deeper look at test operators in scripts, see our Linux shell scripting cheat sheet.

#03

bash if statement: if, elif and else with Real Examples

The basic bash if statement structure looks clean on paper but the full picture includes elif chains and else fallbacks. Here is the complete structure and then several real-world examples.

bash
LinuxTeck.com
#!/bin/bash
# Full if / elif / else structure with input validation

read -p "Enter disk usage percent: " USAGE

# Validate: Ensure input is only numbers
if [[ ! "$USAGE" =~ ^[0-9]+$ ]]; then
echo "Error: Please enter a whole number (e.g., 80 instead of 80%)."
exit 1
fi

if [ "$USAGE" -ge 90 ]; then
echo "CRITICAL: Disk is almost full!"
elif [ "$USAGE" -ge 75 ]; then
echo "WARNING: Disk usage is high."
elif [ "$USAGE" -ge 50 ]; then
echo "INFO: Disk is half full."
else
echo "OK: Disk usage is normal."
fi

OUTPUT
Enter disk usage percent: 82
WARNING: Disk usage is high.

Tip

You can combine multiple conditions on a single if or elif line using && (AND) or || (OR) inside [[ ]]. See the section below on one-liners and the bash exit codes guide for how exit status ties into this.

#04

Real-World Sysadmin Scripts Using Bash if Statements

This is the part that most guides skip entirely. Here are practical scripts you can actually copy and use on a Linux server, whether that is Ubuntu 22.04, Rocky Linux 9, or RHEL.

1. Root Privilege Check

Always check if the user running your script has root access before doing anything that requires it.

bash
LinuxTeck.com
#!/bin/bash
# Check if script runs as root

if [ "$EUID" -ne 0 ]; then
echo "CRITICAL ERROR: This script must be run with sudo or as root."
exit 1
fi

echo "Root check passed. Continuing with administrative tasks..."

2. Check if a Service is Running (systemctl)

bash
LinuxTeck.com
#!/bin/bash
# Check if nginx is active
SERVICE="nginx"

if systemctl is-active --quiet "$SERVICE"; then
echo "$SERVICE is running"
else
echo "$SERVICE is NOT running — attempting restart"
systemctl restart "$SERVICE"
fi

Note

Notice that this if statement has no brackets at all. When you pass a command directly to if, Bash checks the command's exit code. systemctl is-active --quiet returns 0 when active and non-zero when not. This is a core Bash principle. Learn more about it in our guide to bash script exit codes and error handling.

3. Disk Usage Alert Script

This script checks disk usage of the root partition and sends a warning when it goes over 80 percent. Good for cron jobs on production servers.

bash
LinuxTeck.com
#!/bin/bash
# Disk usage alert — works on Ubuntu and Rocky Linux
THRESHOLD=80
USAGE=$(df / | awk "NR==2 {print $5}" | tr -d "%")

if [ "$USAGE" -ge "$THRESHOLD" ]; then
echo "[ALERT] Disk usage is at ${USAGE}% — above threshold of ${THRESHOLD}%"
else
echo "[OK] Disk usage is ${USAGE}% — within safe range"
fi

4. Config File Validation Before Sourcing

bash
LinuxTeck.com
#!/bin/bash
# Safely source a config file only if it exists and is readable
CONFIG="/etc/myapp/app.conf"

if [ -f "$CONFIG" ] && [ -r "$CONFIG" ]; then
source "$CONFIG"
echo "Config loaded from $CONFIG"
else
echo "Config file not found or not readable: $CONFIG"
exit 1
fi

For more real scripts that automate routine server tasks, see the Linux bash scripting automation guide for 2026.

#05

Advanced: Regex Matching, One-Liners, and the case Statement

Regex Matching with =~

The =~ operator inside [[ ]] lets you match strings against a regular expression. This is something most other guides barely mention. Here are three practical examples.

bash
LinuxTeck.com
#!/bin/bash
# 1. Email format check
EMAIL="user@example.com"
if [[ "$EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Valid email: $EMAIL"
else
echo "Invalid email format"
fi

# 2. IP address format check
IP="192.168.1.100"
if [[ "$IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
echo "Looks like a valid IP: $IP"
fi

# 3. Bash version guard
VER=$(bash --version | head -1 | grep -oP "[0-9]+\.[0-9]+" | head -1)
if [[ "$VER" =~ ^[4-9] ]]; then
echo "Bash $VER supports [[ ]] regex matching"
else
echo "Bash version $VER is older than 4 — upgrade recommended"
fi

Inline One-Liners with && and ||

These one-liner patterns are widely used in DevOps pipelines and deployment scripts. They are shorter than writing a full if block when you only need one action.

bash
LinuxTeck.com
#!/bin/bash
# Source config only if readable
[ -f /etc/app.conf ] && source /etc/app.conf || echo "Config not found, using defaults"

# Create directory only if it does not exist
[ -d /var/myapp ] || mkdir -p /var/myapp

# Exit if a required binary is missing
command -v curl >/dev/null 2>&1 || { echo "curl is required but not installed"; exit 1; }

# Short root check for CI pipelines
[ "$EUID" -eq 0 ] && echo "Running as root" || echo "Not root"

The case Statement: A Cleaner Alternative to Long elif Chains

When you find yourself writing five or more elif blocks checking the same variable, the case statement is usually cleaner and faster to read. It also supports pattern matching.

bash
LinuxTeck.com
#!/bin/bash
# case statement — environment selector
read -p "Enter environment (dev/staging/prod): " ENV

case "$ENV" in
dev)
echo "Loading development config"
CONFIG="/etc/app/dev.conf"
;;
staging)
echo "Loading staging config"
CONFIG="/etc/app/staging.conf"
;;
prod|production)
echo "Loading production config"
CONFIG="/etc/app/prod.conf"
;;
*)
echo "Unknown environment: $ENV"
exit 1
;;
esac
echo "Using config: $CONFIG"

#06

Distro-Specific Notes and the set -e Trap

Distro-Specific Shell Behaviour

The shell that runs your script matters a lot and it changes between Linux distributions. Here is a quick summary of what to watch for.

Ubuntu 22.04 / 24.04
/bin/sh is dash, NOT bash. Always use #!/bin/bash when using [[ ]] or (( )).

Confirm your shell: echo $SHELL   and   bash --version

Ubuntu 24.04 ships Bash 5.2 by default.
Rocky Linux 8 / 9 and RHEL
/bin/sh symlinks to bash on these distros — but you should still never rely on that assumption.

Always use #!/bin/bash explicitly. Rocky Linux 9 ships Bash 5.1.

Verify: ls -la /bin/sh   and   /bin/sh --version
CentOS Stream / Fedora
Same rule: /bin/sh may vary. Fedora 40+ ships Bash 5.2.

If your script uses [[ ]], =~, or (( )) — always declare #!/bin/bash at the top.

For a deeper comparison between RHEL-based and Debian-based environments, see our RHEL vs Ubuntu Server comparison.

The set -e + if Statement Trap

Critical Warning: set -e Footgun

When you use set -e (exit on error) in your script, commands inside an if condition are exempt from the exit-on-failure rule. This is actually the correct behaviour but it confuses people who expect set -e to catch every failure.

However, be careful with pipelines. A command like grep something file | head -1 used as an if condition may suppress errors in the middle of the pipe.

Fix: use set -o pipefail alongside set -e to catch pipe failures too.

set -euo pipefail — this is the recommended combination for production bash scripts.

bash
LinuxTeck.com
#!/bin/bash
set -euo pipefail
# set -e: exit on error
# set -u: treat unset variables as errors
# set -o pipefail: catch failures in pipes

CONFIG="/etc/myapp.conf"

# Commands inside if conditions are exempt from set -e
if grep -q "enabled=true" "$CONFIG" 2>/dev/null; then
echo "Feature is enabled"
else
echo "Feature is disabled or config missing"
fi

#07

Troubleshooting Common Bash if Statement Errors

These are the errors that trip up almost every bash learner at some point. Each one has a clear cause and a clear fix.

Error 1: [: missing ]

Cause: Missing space between the bracket and the variable or value.

Wrong: if [$var -gt 0]; then

Fix: if [ $var -gt 0 ]; then — always add spaces inside brackets.

Error 2: unary operator expected

Cause: An unquoted variable is empty. Bash expands [ $VAR -gt 0 ] to [ -gt 0 ] when $VAR is empty, which makes no sense to the test command.

Fix: Always quote string variables: [ "$VAR" -gt 0 ]

Error 3: syntax error near unexpected token 'fi'

Cause: Missing then keyword or a mis-nested fi. Every if block needs a matching then and a matching fi.

Fix: Check that every if has a then on the same or next line and every nested block is closed with its own fi.

Error 4: [[: command not found

Cause: Script is running under #!/bin/sh and the system's sh is dash (common on Ubuntu). Double brackets are a bash-only feature.

Fix: Change the shebang to #!/bin/bash at the very first line of your script.

Error 5: [: too many arguments

Cause: A variable containing spaces is not quoted. [ $FILE -f ] where $FILE is my file.txt gets split into [ my file.txt -f ].

Fix: Always quote file path variables: [ -f "$FILE" ]

Error 6: command not found inside if condition

Cause: Forgot the $ sign before a variable name. if [ VAR -eq 1 ] treats VAR as a literal string, not a variable.

Fix: if [ "$VAR" -eq 1 ] — always use $ to reference variable values. For a comprehensive look at handling errors in scripts, see our bash script exit codes and error handling guide.

FAQ

Frequently Asked Questions

What is the difference between single bracket [ ] and double bracket [[ ]] in bash?

[ ] is the POSIX test command and works in any POSIX shell including sh, dash, and bash. It does not support glob matching, regex with =~, or the &&/|| operators inside the brackets.

[[ ]] is a bash keyword (not a command). It supports glob matching, the =~ regex operator, and &&/|| for combining conditions. It also does not do word splitting, so you can safely omit quotes on variables in most cases. Use [[ ]] for all Bash scripts where you control the shebang. Use [ ] only when writing portable POSIX sh scripts.

How do I use if statement in bash shell script with multiple conditions?

To combine multiple conditions in a single if statement, use && for AND and || for OR inside [[ ]]:

if [[ "$USER" == "admin" && "$EUID" -eq 0 ]]; then
  echo "Authenticated admin"
fi

With single brackets, use -a for AND and -o for OR, or chain two separate bracket tests with && between them:

if [ "$USER" = "admin" ] && [ "$EUID" -eq 0 ]; then
  echo "Authenticated admin"
fi
Can I use if without brackets in bash?

Yes. Bash evaluates the exit code of any command placed after if. If the exit code is 0 (success), the then block runs. This is how service checks work:

if systemctl is-active --quiet nginx; then
  echo "nginx is running"
fi

No brackets needed. The brackets themselves are commands that return an exit code.

How do I check if a variable is empty in bash?

Use -z to check if a string is empty and -n to check if it has content:

NAME=""
if [ -z "$NAME" ]; then
  echo "Name is empty"
fi

if [ -n "$NAME" ]; then
  echo "Name has a value"
fi

Always quote the variable to avoid the "unary operator expected" error.

Does bash if check exit codes or boolean values?

Bash checks exit codes, not boolean values. An exit code of 0 means true (success) and any non-zero value means false (failure). This is the opposite of most programming languages. The test commands [ ] and [[ ]] both return an exit code of 0 when the condition is true and 1 when false. This is why you can write if command; then with no brackets at all.

What does $? return and how is it used with if?

$? holds the exit code of the last executed command. You can use it in an if statement to check whether the previous command succeeded:

cp /etc/hosts /tmp/hosts_backup
if [ $? -eq 0 ]; then
  echo "Backup succeeded"
else
  echo "Backup failed"
fi

However, it is cleaner to use the command directly inside the if: if cp /etc/hosts /tmp/hosts_backup; then. Read more in our bash exit codes guide.

Is elif available in POSIX sh (not just bash)?

Yes, elif is part of the POSIX shell standard and works in sh, dash, bash, and ksh. It is not a bash-only feature. However, [[ ]] inside an elif is bash-only. So the elif keyword is portable but what you put inside the brackets may not be.

END

Summary

The bash if statement is one of the most important tools in Linux shell scripting, and knowing the full picture — [ ] vs [[ ]] vs (( )), all test operators, real sysadmin scripts, and the common errors — is what separates scripts that just run from scripts that hold up in production. For interactive script techniques including how to handle user input with read inside conditional blocks, check out our guide on how to write interactive shell scripts in Linux.

Related Articles

LinuxTeck — A Complete Linux Learning Blog
Learn step-by-step how to automate Linux tasks with real-world scripts and practical examples.


About Sharon J

Sharon J is a Linux System Administrator with strong expertise in server and system management. She turns real-world experience into practical Linux guides on Linux Teck.

View all posts by Sharon J →

Leave a Reply

Your email address will not be published.

L