How to write if else statement in Bash

Jul 28, 2023#bash

In Bash, the if..else statement is a fundamental control structure that allows you to make decisions in your shell scripts based on certain conditions. It provides a way to execute different blocks of code depending on whether a given condition evaluates to true or false.

This conditional branching is essential for creating more complex and dynamic scripts that respond intelligently to various situations.

To write if..else in Bash scripts, you need to use the following syntax:

if first-test-commands; then
  consequent-commands;
[elif more-test-commands; then
  more-consequents;]
[else alternate-consequents;]
fi

There are different test commands syntax depending on the type of condition you want to evaluate and the shell you are using:

  • Single brackets [ expression ]
  • Test command test expression
  • Double brackets [[ expression ]]
  • Double parentheses (( expression ))

Within the condition expression, you can use various operators:

  • Comparison operators (-eq, -ne, -lt, -gt, -le, -ge)
  • String operators (=, !=, -z, -n),
  • File test operators (-e, -f, -d, -r, -w, -x, etc.)

Using single brackets

You can use single brackets ([ ]) in test conditions when you want to use the POSIX test command to check various types of conditions, such as file attributes, string comparisons, numeric comparisons, etc. You need to leave spaces around the brackets and the last argument must be a literal ], to match the opening [.

Single brackets are more portable and compatible with other shells, but they have some limitations and quirks. For example, you need to quote variables to prevent word splitting or globbing, and you need to escape < and > for string comparison. For example:

#!/bin/bash

# Testing if a string is empty
string=""
if [ -z "$string" ]; then
  echo "The string is empty"
fi

# Testing if two strings are equal
string1="hello"
string2="world"
if [ "$string1" = "$string2" ]; then
  echo "The strings are equal"
else
  echo "The strings are not equal"
fi

# Testing if two numbers are greater than or equal to each other
num1=10
num2=5
if [ $num1 -ge $num2 ]; then
  echo "$num1 is greater than or equal to $num2"
fi

# Testing if a string is lexicographically less than another string
string1="apple"
string2="banana"
if [ "$string1" \< "$string2" ]; then
  echo "$string1 comes before $string2"
fi

Using test command

In Bash, the test command is a built-in utility that evaluates expressions and returns a status (exit code) based on whether the expression is true or false. It is often used to perform various tests and comparisons in shell scripts. The test command is also equivalent to using square brackets [ ] for testing conditions, as [ ] is just a symbolic link to the test command.

#!/bin/bash

# Testing if a file exists and is not a symbolic link
file="test.txt"
if test -e "$file" -a ! -L "$file"; then
  echo "$file exists and is not a symbolic link"
fi

# Testing if a directory is writable
dir="mydir"
if test -d "$dir" -a -w "$dir"; then
  echo "$dir is a directory and is writable"
fi

# Testing if a string is empty
string=""
if test -z "$string"; then
  echo "The string is empty"
fi

# Testing if two strings are equal
string1="hello"
string2="world"
if test "$string1" = "$string2"; then
  echo "The strings are equal"
else
  echo "The strings are not equal"
fi

# Testing if two numbers are greater than or equal to each other
num1=10
num2=5
if test $num1 -ge $num2; then
  echo "$num1 is greater than or equal to $num2"
fi

Using double square brackets

In Bash, both single square brackets ([ ]) and double square brackets ([[ ]]) are used to test conditions in if statements, loops, and other control structures. However, there are some key differences between them, and it’s important to use the appropriate form based on the context and requirements of your script.

Using double square brackets is a Bash-specific extension that allows you to use more advanced features than the single square brackets, which are POSIX compliant and more portable. Some of the advantages of using double square brackets are:

  • You can use logical operators like || and && instead of -o and -a
  • You can use regular expression matching with =~
  • You can use < and > for string comparison without escaping
  • You don’t need to quote variables to prevent word splitting or globbing
  • You can use parentheses for grouping without escaping

Here is an example of using double square brackets with regular expressions in Bash:

#!/bin/bash

# Check if a string starts with a vowel
string="apple"
if [[ $string =~ ^[aeiou] ]]; then
  echo "The string starts with a vowel"
else
  echo "The string does not start with a vowel"
fi

The =~ operator inside the double square brackets performs a regular expression match on the left operand (the string) using the right operand (the pattern) as the expression. The ^ in the pattern means the beginning of the string, and [aeiou] means any of the characters inside the brackets. So the condition is true if the string starts with any vowel.

For most cases, it is generally recommended to use double square brackets in Bash scripts. They offer more capabilities, better readability, and reduced quoting issues compared to single square brackets. However, if you are writing scripts that need to be portable across different shells or if you require strict POSIX compliance, using single square brackets may be more appropriate.

Using double parentheses

Using double parentheses (( )) in test conditions in Bash is a way to perform arithmetic evaluation and expansion. You can use them to test numeric expressions and use arithmetic operators such as +, -, *, /, %, **, etc. You can also use them to increment or decrement variables using ++ or --. You don’t need to use the dollar sign ($) to reference variables inside double parentheses.

Here are some examples of using double parentheses in test conditions in Bash:

#!/bin/bash

# Testing if a number is even
num=10
if (( num % 2 == 0 )); then
  echo "$num is even"
fi

# Testing if a number is positive
num=-5
if (( num > 0 )); then
  echo "$num is positive"
else
  echo "$num is not positive"
fi

# Testing if two numbers are equal using variables
a=3
b=4
if (( a == b )); then
  echo "$a and $b are equal"
else
  echo "$a and $b are not equal"
fi

# Incrementing a variable using ++
count=0
(( count++ ))
echo "count is now $count"

Using multiple conditions

You can use multiple conditions in test commands or conditional expressions by using logical operators, such as -a (and), -o (or), && (and), || (or), ! (not), etc. You can also use parentheses to group the conditions and control the order of evaluation. Here are some examples of using multiple conditions:

#!/bin/bash

# Testing if a file exists and is readable or writable
file="test.txt"
if [ -e "$file" ] && [ -r "$file" -o -w "$file" ]; then
  echo "$file exists and is readable or writable"
fi

# Testing if a string is not empty and matches a pattern
string="hello"
if [[ -n "$string" && "$string" == [hH][eE][lL][lL][oO] ]]; then
  echo "The string is not empty and matches the pattern"
fi

# Testing if a number is positive and even
num=10
if (( num > 0 && num % 2 == 0 )); then
  echo "$num is positive and even"
fi

# Testing if a number is not in a range
num=5
if ! (( num >= 10 && num <= 20 )); then
  echo "$num is not in the range [10, 20]"
fi

Using nested if..else statements

A nested if..else statement in Bash is a way to execute different commands or actions based on multiple conditions. You can use the elif keyword to add more branches to the if statement, or you can use another if statement inside the then or else clause.

#!/bin/bash

# Checking the type and permissions of a file
file="test.txt"
if [ -e "$file" ]; then
  echo "$file exists"
  if [ -f "$file" ]; then
    echo "$file is a regular file"
    if [ -r "$file" ]; then
      echo "$file is readable"
    fi
    if [ -w "$file" ]; then
      echo "$file is writable"
    fi
    if [ -x "$file" ]; then
      echo "$file is executable"
    fi
  elif [ -d "$file" ]; then
    echo "$file is a directory"
  elif [ -L "$file" ]; then
    echo "$file is a symbolic link"
  else
    echo "$file is of unknown type"
  fi
else
  echo "$file does not exist"
fi

Bash, POSIX and other shells

Bash, POSIX and other shells are related to each other in terms of their history, features, compatibility and standards. Here are some of the main points of their relationship:

Bash is a command-line interpreter that is widely used in Linux and other Unix-like systems. It is a superset of sh, which means it supports all the features of sh and provides more functionality than sh. Bash is not a POSIX-compliant shell, but it is intended to be a conformant implementation of the Shell and Utilities portion of the IEEE POSIX specification (IEEE Standard 1003.1).

POSIX is a family of standards that define how a POSIX-compliant operating system should behave and work. It includes a standard for the shell language and utilities, which specifies the syntax, semantics and behavior of various commands and features. POSIX-compliant shells are shells that follow the POSIX standard and can run on any POSIX-compliant system. Some examples of POSIX-compliant shells are dash, ksh, zsh, etc.

Other shells are command-line interpreters that have different features, syntax and behavior than Bash or POSIX shells. They may be compatible or incompatible with Bash or POSIX to some extent, depending on their design and implementation. Some examples of other shells are csh, tcsh, fish, etc.