iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

if / case

Bash conditionals come in two flavours: `[[ ... ]]` (modern, safe) and `[ ... ]` (POSIX, fragile). Combine with `&&`, `||`, `if`, `case`, and short-circuit patterns to write scripts that read like prose. Quoting still matters; ShellCheck still catches the rest.

if / case / [[ ]] / && / ||

EXAMPLE
#!/usr/bin/env bash
set -Eeuo pipefail

# ===== 1) Test command: [[ ... ]] vs [ ... ] =====
# Prefer [[ ... ]] — it does not word-split, supports patterns + regex, safer.

name='alice'
if [[ "$name" == 'alice' ]]; then echo 'match'; fi   # double bracket
if [ "$name" = 'alice' ];  then echo 'match'; fi    # POSIX (single =)

# ===== 2) String comparisons =====
[[ -z "$name" ]]              # zero length (empty)
[[ -n "$name" ]]              # non-empty
[[ "$name" == 'alice' ]]      # equals
[[ "$name" != 'bob' ]]        # not equals
[[ "$name" < 'zelda' ]]       # lexicographic <
[[ "$name" == a* ]]           # glob match
[[ "$name" =~ ^[a-z]+$ ]]    # regex match (BASH_REMATCH for captures)

# ===== 3) Numeric comparisons =====
n=5
[[ $n -eq 5 ]]                # equals (numeric)
[[ $n -ne 0 ]]                # not equals
[[ $n -lt 10 ]]               # less than
[[ $n -le 10 ]]               # less or equal
[[ $n -gt 0 ]]                # greater than
[[ $n -ge 1 ]]                # greater or equal
(( n > 0 && n < 100 ))         # C-style arithmetic test

# ===== 4) File tests =====
[[ -e /etc/hosts ]]            # exists
[[ -f /etc/hosts ]]            # regular file
[[ -d /etc ]]                  # directory
[[ -L /usr/bin/python3 ]]      # symlink
[[ -r /etc/hosts ]]            # readable
[[ -w /tmp ]]                  # writable
[[ -x /usr/bin/git ]]          # executable
[[ -s /var/log/app.log ]]      # exists and size > 0
[[ a.txt -nt b.txt ]]           # newer than
[[ a.txt -ot b.txt ]]           # older than

# ===== 5) if / elif / else =====
if [[ -d /etc/nginx ]]; then
  echo 'nginx present'
elif [[ -d /etc/apache2 ]]; then
  echo 'apache present'
else
  echo 'no web server config dir'
fi

# ===== 6) case — multi-way branch =====
read -rp 'env > ' env
case "$env" in
  dev|development)  config='dev.env' ;;
  stage|staging)    config='stage.env' ;;
  prod|production)  config='prod.env' ;;
  *)                echo 'unknown env'; exit 2 ;;
esac
echo "using $config"

# ===== 7) Short-circuit && / || =====
[[ -f config.toml ]] && echo 'have config' || echo 'missing'
# Use carefully — when the && branch fails, || runs as if 'missing'.
# For complex logic, use 'if'.

# Guard patterns
require_root() { [[ $EUID -eq 0 ]] || { echo 'must be root' >&2; exit 1; }; }
require_command() { command -v "$1" >/dev/null || { echo "need $1" >&2; exit 1; }; }

# ===== 8) Combine with parameter expansion =====
mode="${1:-dry-run}"
case "$mode" in
  dry-run) echo 'dry run only' ;;
  apply)   echo 'applying changes' ;;
  *)       echo 'usage: $0 dry-run|apply'; exit 2 ;;
esac

# ===== 9) Trapping errors =====
trap 'echo "ERROR on line $LINENO. cmd: $BASH_COMMAND" >&2' ERR

# ===== 10) Common pitfalls =====
# - Using = in [[ ]] (works) vs == (also works) — be consistent
# - Comparing numbers with ==  (string comparison; '5' != '05')
#   Use -eq for numbers
# - Forgetting to quote: [[ $x = foo ]] fails if x is empty
#   Always: [[ "$x" == 'foo' ]]
# - Globs without quotes leak to the test — quote the literal:
#   [[ "$name" == a* ]]   (right side NOT quoted -> glob match)
#   [[ "$name" == 'a*' ]] (right side quoted -> literal 'a*')

# ===== 11) Bash booleans + return codes =====
# In bash, EXIT CODE 0 means SUCCESS (truth), non-zero is failure.
# Functions can be used directly as conditions.
is_dir() { [[ -d "$1" ]]; }
if is_dir /etc; then echo 'yes'; fi

# ===== 12) ShellCheck catches almost everything =====
shellcheck script.sh

Why it matters

Default to `[[ ... ]]` for tests; it does not word-split, supports glob + regex, and is safer than POSIX `[ ... ]`. Combined with `case` for multi-way branches and `(( ... ))` for arithmetic, you can write conditionals that read as prose without the quoting horrors of legacy shell.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
if [[ -f /etc/hosts ]]; then
    echo "hosts exists"
fi

case "$1" in
    start) start ;;
    stop)  stop  ;;
esac
Try it Yourself »

Discussion

Loading…