Bash scripts often fail in subtle ways—not because of syntax errors, but because conditionals are written with the wrong operators or without proper quoting. These small mistakes can cause your script to execute the wrong branch, skip intended logic, or even break entirely.

In this guide, we’ll explore the correct ways to write reliable Bash conditionals. You’ll learn how to:

  • Use the modern [[ ]] test syntax for strings, numbers, and files.
  • Perform arithmetic with (( )).
  • Ensure portability with POSIX [ ].
  • Replace long if chains with case.
  • Debug branching errors effectively.

Follow these methods, and your Bash scripts will behave exactly as intended—no surprises.

Method 1: Writing if...else with Bash [[ ]]

The [[ ]] syntax is Bash’s modern test command. It prevents accidental word splitting, wildcard expansion, and unexpected results.

Step 1: Basic [[ ]] Conditional

#!/usr/bin/env bash
set -euo pipefail

read -r -p "Enter a value: " val

if [[ "$val" == "admin" ]]; then
  echo "Welcome, admin."
else
  echo "Access limited."
fi

Step 2: Comparing Strings

Always quote variables to protect against empty values or spaces.

user="alice"
target="alice"

if [[ "$user" == "$target" ]]; then
  echo "Usernames match."
else
  echo "Usernames differ."
fi

Step 3: Numeric Comparisons

For integers in [[ ]], use -eq, -ne, -gt, -lt, etc.

read -r -p "Enter a number: " n

if [[ "$n" -gt 10 ]]; then
  echo "Greater than 10."
elif [[ "$n" -eq 10 ]]; then
  echo "Equal to 10."
else
  echo "Less than 10."
fi

Step 4: File Checks

path="./data.txt"

if [[ -f "$path" ]]; then
  echo "File exists."
else
  echo "Creating file..."
  : > "$path"
fi

Step 5: Combining Conditions

file="./report.log"
size=5

if [[ -f "$file" ]] && [[ "$size" -ge 5 ]]; then
  echo "Process report."
fi

role="staff"
if [[ "$role" == "admin" || "$role" == "staff" ]]; then
  echo "Privileged."
fi

Step 6: Using elif for Efficiency

status="warning"

if [[ "$status" == "error" ]]; then
  echo "Exit immediately."
  exit 1
elif [[ "$status" == "warning" ]]; then
  echo "Log and continue."
else
  echo "All good."
fi

Method 2: Arithmetic with (( ))

When working exclusively with integers, (( )) provides a cleaner syntax.

Step 1: Simple Math Comparisons

a=12 b=8

if (( a > b )); then
  echo "a is larger."
elif (( a == b )); then
  echo "Equal."
else
  echo "b is larger."
fi

Step 2: Multiple Numeric Conditions

x=7 y=3 z=10

if (( (x > y) && (z >= 10) )); then
  echo "Threshold met."
fi

Step 3: Input Validation

read -r n
if [[ "$n" =~ ^-?[0-9]+$ ]] && (( n >= 0 )); then
  echo "Non-negative integer."
else
  echo "Invalid number."
fi

Method 3: POSIX [ ] for Portability

Use [ ] if your script must run in /bin/sh or other shells.

#!/bin/sh
a="hello"
b="hello"

if [ "$a" = "$b" ]; then
  echo "Match."
else
  echo "No match."
fi

Numeric comparison:

a=5 b=30
if [ "$a" -lt "$b" ]; then
  echo "a is less than b."
fi

Lexicographic string comparison:

x="apple" y="banana"
if [ "$x" \< "$y" ]; then
  echo "apple comes before banana."
fi

Method 4: Simplify with case

When you need to branch based on a single variable’s value, case is cleaner than multiple if statements.

read -r -p "Enter mode (start|stop|status): " mode

case "$mode" in
  start)  echo "Starting...";;
  stop)   echo "Stopping...";;
  status) echo "Service is running.";;
  *)      echo "Unknown mode."; exit 1;;
esac

Multiple matches:

level="warn"

case "$level" in
  error|err)      echo "Exit with failure."; exit 1;;
  warn|warning)   echo "Log warning.";;
  info|debug)     echo "Proceed normally.";;
  *)              echo "Unrecognized level.";;
esac

Method 5: Debugging and Best Practices

  • Group conditions with parentheses for clarity.
  • Use == for strings, -eq for integers.
  • Always quote variables in [ ] and [[ ]].
  • Enable tracing to debug:
set -x  # trace on
# conditions here
set +x  # trace off
  • Keep indentation and spacing consistent for readability.

Quick Operator Reference

  • Strings: ==, !=, -n var (non-empty), -z var (empty)
  • Integers: -eq, -ne, -gt, -lt, or < > == in (( ))
  • Files: -f, -d, -e, -x, -r, -w
  • Logic: && (AND), || (OR), ! (NOT)

Conclusion

Bash branching mistakes are usually caused by the wrong test syntax, mismatched operators, or missing quotes. By using the right test form for each situation—[[ ]] for Bash, (( )) for math, and [ ] for portability—you can write clean, predictable scripts that won’t surprise you. Add clear formatting, validate inputs, and debug with tracing, and your Bash conditionals will work every single time.

Did you enjoy this article? Feel free to share it on social media and subscribe to our newsletter so you never miss a post!

And if you'd like to go a step further in supporting us, you can treat us to a virtual coffee ☕️. Thank you for your support ❤️!
Buy Me a Coffee

Categorized in: