Conditionals: Making Decisions in Scripts

Make your scripts decide things with if, elif, else, the test command and the case statement.

~8 min Beginner

Scripts that decide

A conditional lets a script check something and choose what to do. For example: if a file already exists, do not overwrite it; if a number is too large, print a warning.

The if statement

#!/bin/bash
age=20
if [ $age -ge 18 ]; then
    echo "You are an adult"
fi

The parts:

  • if starts the check.
  • [ ... ] is the test. It succeeds (is true) or fails (is false). Spaces inside the brackets are required.
  • then starts the block of commands that runs when the test is true.
  • fi ("if" backwards) ends the whole statement.

The semicolon before then ends the test line. You can also put then on its own line instead.

Comparing numbers

Inside [ ] Bash uses letters, not symbols, to compare numbers:

  • -eq equal
  • -ne not equal
  • -gt greater than
  • -ge greater than or equal
  • -lt less than
  • -le less than or equal
if [ "$count" -gt 10 ]; then
    echo "Lots of files"
fi

This test is true when $count is greater than 10.

Comparing text

  • = equal
  • != not equal
  • -z "$s" true if the text is empty
  • -n "$s" true if the text is not empty
if [ "$USER" = "root" ]; then
    echo "Careful, you are root"
fi

Always put double quotes around variables in tests. If a variable is empty and unquoted, the test loses an argument and fails with a syntax error.

elif and else

score=72
if [ "$score" -ge 90 ]; then
    echo "Grade A"
elif [ "$score" -ge 70 ]; then
    echo "Grade B"
else
    echo "Keep practising"
fi

elif means "else if" and adds another test. else runs when no test matched. The tests are checked from top to bottom, and only the first true block runs. Here the score is 72, so the output is Grade B.

Testing files

Scripts often ask questions about files and folders.

  • -e path exists
  • -f path is a regular file
  • -d path is a directory
  • -r, -w, -x is readable, writable, executable
  • -s path exists and is not empty
if [ -f "notes.txt" ]; then
    echo "Found it"
else
    echo "Missing, creating it"
    touch notes.txt
fi

Combining conditions

if [ "$age" -ge 18 ] && [ "$age" -lt 65 ]; then
    echo "Working age"
fi

if [ "$day" = "Sat" ] || [ "$day" = "Sun" ]; then
    echo "Weekend"
fi

if [ ! -d "$dir" ]; then
    echo "Directory does not exist"
fi
  • && means and: both tests must be true.
  • || means or: at least one must be true.
  • ! means not: it reverses a test. [ ! -d "$dir" ] is true when $dir is not a directory.

The [[ ]] form

Bash also has [[ ... ]]. It is a Bash feature that behaves more safely: it handles empty variables without quotes, allows == and && inside the brackets, and supports pattern matching.

if [[ $name == A* ]]; then
    echo "Name starts with A"
fi

Use [ ] when a script must work in other shells, and [[ ]] in scripts that only run in Bash.

case: many choices

When you compare one value to many options, case is tidier than a long elif chain.

read -p "Start, stop or restart? " action
case "$action" in
    start)   echo "Starting..." ;;
    stop)    echo "Stopping..." ;;
    restart) echo "Restarting..." ;;
    *)       echo "Unknown option: $action" ;;
esac

(read -p asks the user to type something and stores it in the variable. It is covered in a later lesson.)

Each pattern ends with ), each block ends with ;;, the * pattern matches anything not listed above, and esac ("case" backwards) ends the statement.

The most common beginner bug is missing spaces. [$a -eq 1] fails, but [ $a -eq 1 ] works. The [ is actually a command, so it needs spaces around it like any other command.
Sign up to track your progress Mark lessons as read and pick up where you left off Sign up free to unlock this practice Your first practice lesson is free to try. Create an account to unlock the rest and save your progress