7 min read

How to Use If-Else Statements and Conditionals in Bash

Table of Contents

In Bash scripting, being able to make decisions is fundamental. You often need your script to perform different actions based on whether a file exists, a variable has a certain value, or a command succeeded. This is where if-else statements and conditionals come in. They are the core of logical control flow in your scripts.

This guide will walk you through everything you need to know, from the basic concept of an exit status to writing complex, multi-layered conditions.

The Foundation: Understanding Exit Status

Before we write our first if statement, we need to understand how Bash decides if something is “true” or “false”. Every command you run in Linux finishes with an exit status (also called a return code).

  • 0 means the command was successful.
  • Any number other than 0 (from 1 to 255) means the command failed.

You can see the exit status of the last command by checking the special variable $?.

Let’s try it. First, a successful ls command:

ls /etc/hosts
echo $?

The output of the echo command will be 0. Now, let’s try a command that fails:

ls /etc/non_existent_file
echo $?

This time, ls prints an error, and echo $? will show a non-zero number (like 2), indicating failure. The if statement is designed to act on this exact principle.

Step 1: The Basic if Statement

The simplest conditional checks if a command’s exit status is 0. If it is, the code inside the then block is executed.

The syntax is: if [ condition ]; then ... fi

Let’s break this down:

  • if: The keyword that starts the conditional block.
  • [ condition ]: This is a shortcut for the test command. It evaluates the condition and returns an exit status of 0 (true) or 1 (false). Crucially, you must have spaces around the brackets and around the operators inside them!
  • then: The keyword that starts the code block to be executed if the condition is true.
  • fi: The if statement spelled backward, which closes the block.

Example: Check if a file exists

The -f operator tests if a given path exists and is a regular file.

#!/bin/bash

FILENAME="my_document.txt"

if [ -f "$FILENAME" ]; then
  echo "$FILENAME exists."
fi

echo "Script finished."

If my_document.txt exists in the same directory, the script will print that it exists. If not, it will do nothing and just print “Script finished.”

Step 2: Adding an else Block

What if you want to do something when the condition is not met? That’s what the else block is for.

The syntax is: if [ condition ]; then ... else ... fi

Example: Check for a directory and create it if it doesn’t exist

The -d operator tests if a path is a directory.

#!/bin/bash

DATA_DIR="/var/log/my_app"

if [ -d "$DATA_DIR" ]; then
  echo "Directory $DATA_DIR already exists."
else
  echo "Directory $DATA_DIR not found. Creating it now..."
  mkdir -p "$DATA_DIR"
fi

This is a very common and practical use case for if-else in system administration scripts.

Step 3: Chaining Conditions with elif

Sometimes you need to check more than one condition. You can chain multiple checks together using elif (short for “else if”).

The syntax is: if [ condition1 ]; then ... elif [ condition2 ]; then ... else ... fi

Example: Greet a user based on their username

#!/bin/bash

# The $USER variable automatically holds the current user's name
if [ "$USER" == "root" ]; then
  echo "Welcome, Administrator. You have ultimate power."
elif [ "$USER" == "guest" ]; then
  echo "Welcome, Guest. Your access is limited."
else
  echo "Welcome, $USER."
fi

The script checks conditions from top to bottom. As soon as it finds a true condition, it executes that block and skips the rest of the if/elif/else structure.

Step 4: Common Conditional Operators

The test command ([ ... ]) provides a rich set of operators for different kinds of comparisons.

File Operators

OperatorDescription
-e fileTrue if file exists.
-f fileTrue if file exists and is a regular file.
-d dirTrue if dir exists and is a directory.
-s fileTrue if file exists and is not empty.
-r fileTrue if file is readable by you.
-w fileTrue if file is writable by you.
-x fileTrue if file is executable by you.

String Operators

OperatorDescription
str1 = str2True if str1 is identical to str2. Use == for better readability.
str1 != str2True if the strings are not identical.
-z strTrue if the string str is empty (zero length).
-n strTrue if the string str is not empty.

Pro Tip: Always quote your variables (e.g., "$VAR") inside test conditions to prevent errors if the variable is empty or contains spaces.

Integer Operators

OperatorDescription
int1 -eq int2Equal
int1 -ne int2Not Equal
int1 -gt int2Greater Than
int1 -ge int2Greater Than or Equal To
int1 -lt int2Less Than
int1 -le int2Less Than or Equal To

Step 5: The Modern Approach: Double Brackets [[ ... ]]

While single brackets [ ] are POSIX-compliant and work everywhere, Bash offers an enhanced version: double brackets [[ ]]. They are generally safer and more powerful.

Key Advantages of [[ ... ]]:

  1. No word splitting: You don’t strictly need to quote variables, as they won’t be split by spaces. (It’s still good practice, though!)
  2. C-style logical operators: You can use && for AND and || for OR.
  3. Pattern matching: Supports == and != with shell globbing (e.g., [[ $file == *.txt ]]).
  4. Regex matching: Use the =~ operator for regular expression matching.

Example: Using && and Regex

This script checks if a variable contains only numbers.

#!/bin/bash

INPUT="12345"

if [[ "$INPUT" =~ ^[0-9]+$ && ${#INPUT} -gt 3 ]]; then
  echo "'$INPUT' is a number and is longer than 3 digits."
else
  echo "'$INPUT' is not a valid ID."
fi

Here, [[ "$INPUT" =~ ^[0-9]+$ ]] checks if the input matches the regex for one or more digits, and && ${#INPUT} -gt 3 checks if its length is greater than 3. This kind of complex check is much cleaner with double brackets.

Conclusion

You’ve now learned the essentials of conditional logic in Bash. By understanding exit status and mastering the if-elif-else-fi structure, you can make your scripts smarter, more robust, and capable of handling a wide variety of situations.

Key Takeaways:

  • Every command has an exit status: 0 for success, non-zero for failure.
  • The basic structure is if [ condition ]; then ... fi.
  • Use else for a fallback action and elif for multiple checks.
  • Always quote your variables inside conditionals, especially when using single brackets [ ].
  • For modern Bash scripting, prefer the more powerful and safer double brackets [[ ]].

As a next step, consider learning about case statements, which can be a cleaner alternative to long if/elif chains when you’re checking a single variable against multiple possible values. Happy scripting