Premium lesson

Controlling the Execution Flow With Conditions in Bash

Scripting·51 min read·Jan 1, 2025

In programming, a control statement is a code structure used to manage the flow and logic of a script by conditionally executing (or not executing) a set of instructions based on predicates called conditions.

Conditions and operators

A condition is an expression that when logically evaluated produces a boolean result, which translates to either true or false, that determines whether code should or shouldn't be executed.

These conditions are created using comparison operators, such as == or -eq, that allow to logically compare values between them.

Comparing strings

Checking the identically

To check strings identically, you can use:

  • == to check if two strings are identical.

  • != to check if two strings are different.

For example:

# This condition evaluates to `true` as both strings are identical
"hello" == "hello"

# This condition evaluates to `true` as both strings are different
"hello" != "world"

Checking the lexicographical order

To check strings lexicographical order, you can use:

  • < to check if a string sorts before another.

  • > to check if a string sorts after another.

For example:

# This condition evaluates to `true` as 'a' sorts before 'o'
"jack" < "john"

# This condition evaluates to `true` as 'o' sorts after 'a'
"john" > "jack"

Checking pattern matching

To test a string against a regular expression pattern, you can use the =~ operator.

For example:

# This condition evaluates to `true` as the string contains at least one number
"h3llo" =~ [0-9]+

# This condition evaluates to `true` as the string is a valid phone number
"+33698765432" =~ ^(\+33){1}[0-9]{9}$

# This condition evaluates to `true` as the string only contains letters
"helloworld" =~ ^[[:alpha:]]+$

Comparing numbers

Checking the equality

To check numbers equality, you can use:

  • -eq to check if two numbers are equal.

  • -ne to check if two numbers are not equal.

For example:

# This condition evaluates to `true` as both numbers are equal
123 -eq 123

# This condition evaluates to `true` as both numbers are unequal
123 -ne 321

Checking the inferiority and superiority

To check numbers inferiority, you can use:

  • -lt to check if a number is lesser than another.

  • -le to check if a number is lesser or equal to another.

To check numbers superiority, you can use:

  • -gt to check if a number is greater than another.

  • -ge to check if a number is greater or equal to another.

For example:

# This condition evaluates to `true` as 10 is lesser than 20
10 -lt 20

# This condition evaluates to `true` as 10 is lesser than or equal to 10
10 -le 10

# This condition evaluates to `true` as 20 is greater than 10
20 -gt 10

# This condition evaluates to `true` as 20 is greater than or equal to 20
20 -ge 20

Conditional statements

In programming, conditional expressions alone don't really make sense as they are not enough to determine whether certain code instructions should or shouldn't be executed.

They have to be evaluated by one of the following control statements in charge of deciding on the execution logic of the script.

The if statement

The if statement is used to execute a set of instructions based on the boolean evaluation of a condition.

if [[ condition ]]; then
  instructions
fi

If the condition logically evaluates to true, the instructions between the then and fi keywords are then executed; otherwise, they are ignored.

Note:

It is possible to negate (or invert) the logical evaluation of a condition using the NOT logical operator !.

if [[ ! condition ]]; then
  instructions
fi

In this case, if the condition logically evaluates to false, the instructions between the then and fi keywords are then executed; otherwise, they are ignored.

Example

Let's consider this script, that checks whether two strings are identical or different:

#!/bin/bash

if [[ $1 == $2 ]]; then
  echo "Strings are identical"
fi

if [[ $1 != $2 ]]; then
  echo "Strings are not identical"
fi

When executed, it will:

  1. Check if the first positional argument $1 is identical to the second positional argument $2 using the string equality operator ==.

  2. Output the string "Strings are identical" if the condition logically evaluates to true.

  3. Check if the first positional argument $1 is different from the second positional argument $2 using the string inequality operator !=.

  4. Output the string "Strings are not identical" if the condition logically evaluates to true.

Which will produce this output:

$ ./script.sh hello hello
Strings are identical
$ ./script.sh hello world
Strings are not identical

The else statement

The else statement, in conjunction with the if statement, is used to define a set of instructions that should be executed when the condition specified in the if statement logically evaluates to false.

if [[ condition ]]; then
  instructions
else
  instructions
fi

Note: It is common to say that a condition is met when it evaluates to true, and unmet otherwise.

Example

Let's consider this script, that checks whether an integer is even or odd:

#!/bin/bash

remainder=$(($1 % 2))

if [[ $remainder -eq 0 ]]; then
  echo "Number is even"
else
  echo "Number is odd"
fi

Note: In programming, the modulo operator % is used to calculate the remainder of the division of two integers. For example, 10 % 5 = 0 and 10 % 3 = 1.

When executed, it will:

  1. Check if the remainder of the division of the first positional argument $1 by 2 equals 0.

  2. If it evaluates to true, output the string "Number is even".

  3. Otherwise, output the string "Number is odd".

Which will produce this output:

$ ./script.sh 2
Number is even
$ ./script.sh 1
Number is odd

The elif statement

The elif statement (short for "else if"), in conjunction with the if-else statement, is used to test multiple conditions sequentially and execute different sets of instructions based on the first condition that logically evaluates to true.

if [[ condition ]]; then
  instructions
elif [[ condition ]]; then
  instructions
else
  instructions
fi

Example

Let's consider this script, that checks whether a number is negative, positive, or zero:

#!/bin/bash

if [[ $1 -lt 0 ]]; then
  echo "The number is negative"
elif [[ $1 -gt 0 ]]; then
  echo "The number is positive"
else
  echo "The number is zero"
fi

When executed, it will:

  1. Check if the first positional argument $1 is less than 0 and output the string "The number is negative".

  2. Otherwise, check if the first positional argument $1 is greater than 0 and output the string "The number is positive".

  3. Otherwise, output the string "The number is zero".

Which will produce this output:

$ ./script.sh -1
The number is negative
$ ./script.sh 0
The number is zero
$ ./script.sh 1
The number is positive

The case statement

The case statement is used to evaluate a single variable or expression against a list of patterns or values, and execute different sets of instructions based on the match.

case variable in
  pattern)
    instructions
    ;;
  pattern)
    instructions
    ;;
  *)
    instructions
    ;;
esac

Where:

  • The double semicolon ;; indicates the end of a set of instructions.

  • The wildcard * is used as a fallback value that matches all other cases if none of the previous patterns are matched.

Note: The wildcard pattern is optional and must always be declared last.

Example

Let's consider this script, that translates numbers into week days:

#!/bin/bash

case $1 in
  1)
    echo "Monday"
    ;;
  2)
    echo "Tuesday"
    ;;
  3)
    echo "Wednesday"
    ;;
  4)
    echo "Thursday"
    ;;
  5)
    echo "Friday"
    ;;
  6)
    echo "Saturday"
    ;;
  7)
    echo "Sunday"
    ;;
  *)
    echo "Error"
    ;;
esac

When executed, it will:

  1. Check if the first positional argument $1 matches any of the listed numbers from 1 to 7 and output the string corresponding to the day of the week.

  2. Otherwise, output the string "Error".

Which will produce this output:

$ ./script.sh 1
Monday
$ ./script.sh 3
Wednesday
$ ./script.sh 9
Error

Nesting conditional statements

A nested conditional statement is a statement placed inside another statement to create complex decision-making structures, allowing you to evaluate multiple conditions and execute different instructions based on these conditions.

Just like with any other instructions, each inner statement is executed based on the outcome of the outer statement, and so on.

Nesting if, elif, and else statements

When placing an if statement within another if statement, the second statement will only be evaluated if the first one evaluates to true.

if [[ condition ]]; then
  if [[ condition ]]; then
    instructions
  fi
fi

When placing an if statement within another elif statement, the second statement will only be evaluated if the first one evaluates to false.

if [[ condition ]]; then
  instructions
elif
  if [[ condition ]]; then
    instructions
  fi
else
  instructions
fi

When placing an if statement within another else statement, the second statement will only be evaluated if the first one evaluates to false.

if [[ condition ]]; then
  instructions
else
  if [[ condition ]]; then
    instructions
  fi
fi

Example

Let's consider this script, that outputs the type of motorbike based on its brand and model:

#!/bin/bash

brand=$1
model=$2

if [[ $brand == "Honda" ]]; then
  if [[ $model == "CB500X" ]]; then
    echo "Trail"
  else
    echo "Unknown model"
  fi
else
  echo "Unknown brand"
fi

When executed, it will:

  1. Declare a variable named brand and initialize it with the value of the 1st positional argument $1

  2. Declare a variable named model and initialize it with the value of the 2nd positional argument $2

  3. Check if the value of the brand variable is identical to the string "Honda" using the == operator, or output the string "Unknown brand" otherwise.

  4. Check if the value of the model variable is identical to the string "CB500X" using the == operator and output the string "Trail", or output the string "Unknown model" otherwise.

Which will produce this output:

$ ./script.sh Honda CB500X
Trail
$ ./script.sh Honda SR1000RR
Unknown model
$ ./script.sh Yamaha MT09
Unknown brand

Nesting case statements

Nesting a case statement is quite similar to nesting other statements, as it will only be executed if the first variable matches the pattern it is defined under.

case variable in
  pattern)
    instructions
    ;;
  pattern)
    case variable in
      pattern)
        instructions
        ;;
    esac
    ;;
  *)
    instructions
    ;;
esac

Example

Let's consider this script, that outputs the type of motorbike based on its brand and model:

#!/bin/bash

brand=$1
model=$2

case $brand in
  Honda)
    case $model in
      CB500X)
        echo "Trail"
        ;;
      *)
        echo "Unknown model"
        ;;
    esac
    ;;
  *)
    echo "Unknown brand"
    ;;
esac

When executed, it will perform the same logic as the previous script and produce the same output.

Combining multiple conditions

It often happens that a set of instructions requires more than one condition in order to be executed.

Rather than unnecessarily nesting multiple if statements:

if [[ condition ]]; then
  if [[ condition ]]; then
    instructions
  fi
fi

You can use the && (AND) and || (OR) logical operators to combine multiple if statements into a single one:

if [[ condition && condition ]]; then
  instructions
fi

Note: Logical operators also work with the elif statement.

Example

Let's consider this script, that outputs whether a shop is open or closed:

#!/bin/bash

day=$1
time=$2

if [[ $day == "Monday" && $time -ge 6 ]]; then
  echo "Open"
elif [[ $day == "Wednesday" || $day == "Friday" && $time -lt 11 ]]; then
  echo "Open"
else
  echo "Closed"
fi

When executed, it will:

  1. Declare a variable named day and initialize it with the value of the 1st positional argument $1.

  2. Declare a variable named time and initialize it with the value of the 2nd positional argument $2.

  3. Check if the value of the day variable equals the string "Monday" and the value of the time variable is greater than or equal to 6.

  4. Output the string "Open" if it evaluates to true.

  5. Check if the value of the day variable equals the string "Wednesday" or "Friday" and the value of the time variable is lesser than or equal to 11.

  6. Output the string "Open" if it evaluates to true.

  7. Otherwise, output the string "Closed".

Which will produce this output:

$ ./script.sh Monday 6
Open
$ ./script.sh Tuesday 6
Closed
$ ./script.sh Wednesday 9
Open
$ ./script.sh Friday 9
Open
$ ./script.sh Friday 11
Closed

🗒️ Summary

Here's a summary of what you've learned in this lesson:

  • A condition is an expression that when evaluated produces a boolean result.

  • The ==, !=, >, and < operators are used to compare strings.

  • The -eq, -ne, -lt, -le, -gt, and -ge operators are used to compare numbers.

  • A control statement is a code structure used to manage the flow and logic of a script.

  • The if, elif, else, and case are control statements that use conditions to selectively execute sets of instructions.

  • The ! operator is used to negate a condition.

  • Control statements can be nested to create complex decision-making structures.

  • Conditions can be combined using the && and || logical operators.

🤖 Projects

Here's a list of projects to apply what you've just learned:

  • lb_calculator: Write a script that prints the result of an arithmetic operation.
icon light bulb key

Unlock the CLI & Scripting with Bash module

Learn how to gain advanced control over the OS and automate complex routine tasks prone to manual errors with the CLI and Bash scripting.

You get immediate access to:

  • 34 focused lessons across the CLI and Bash
  • 4 real-world projects with commented solutions
  • Ongoing updates to this bundle
  • Lifetime access to this bundle
Unlock this module