If statements in Bash let us make decisions. The basic syntax is:

if <command>; then
fi

command can be a function or a program.

With what we know so far lets make a script that searches a file for some text and prints "found it!" if it finds the text.

#!/bin/bash

function main {
  if grep -q $1 $2; then #(1) (2) (3)
    echo "found it!"
  fi
}

main $@
  1. grep is a program that runs a regular expression search on the file. Regular expressions are a complicated topic and some of it will be touched on later.

  2. We use positional arguments 1 and 2. The first is the string to find. The second is the name of the file.

  3. -q option to grep means quiet. It suppresses output from grep.

Example
./found-it.sh "command" bash-0-to-100.adoc
found it!

Here we search of the string command in this file.

If it finds the string then grep returns 0. If not it returns 1. This might surprise you. In shell script 0 is true and any other value is interpreted as false.

We can also use if statements with functions we define. Let’s create a function quiet_grep which calls grep with -q.

quiet grep
#!/bin/bash

function quiet_grep {
  if grep -q $1 $2; then
    return 0 #(1)
  else
    return 1
  fi
}

function main {
  if quiet_grep $1 $2; then #(2)
    echo "found it!"
  fi
}

main $@
  1. Note the return value of 0 for truth.

  2. Call our new function quiet_grep.

Important
Bash uses 0 for truth and any other value as false. This is different from other programming languages.

Can we use if statements with variables as in other languages?

VAR=1
if $VAR; then
  echo "yes"
fi
output
bash: 1: command not found

Doesn’t look like it. This isn’t how other languages work. What’s going on? The reason is in the grammar of the if statement. The stuff that follows the if has to be a command.

Important
if statements run a command. You can’t use a parameter directly in an if statement.

If you can’t directly use a parameter in an if statement, how do you test a value of a parameter? If statements require a command which implies that there must be a command to test parameter values. It’s called test. You can see how to use it in the next example.

VAR=1
if test $VAR -eq 1; then #(1)
  echo "yes"
fi
  1. -eq is short for equals

There are many other options to test. At the command prompt type man test to see the manual for that command. You can move up and down inside the pager using j and k. Use q to quit.

But writing test everytime I want to test something is awkward. Is there another way? Yes.

VAR=1
if [ $VAR -eq 1 ]; then #(1)
  echo "yes"
fi
  1. [ is also a command.

But I thought you said if statements run commands only? Yes, that’s true. [ is a command. It’s often installed under /usr/bin.

ls -l '/usr/bin/['
-rwxr-xr-x 1 root root 59528 Mar  7 00:01 '/usr/bin/['
Note
Implementations of Bash will implement [ as a builtin command. In other words it runs in the same process as the interpreter and the external command /usr/bin/[ isn’t called.

Numeric and String comparisons

When comparing strings and numbers test and [ take different comparions parameters. Generally if conventional boolean operators are used, then it’s a string comparison taking place. If it’s -eq or -gt, single dash options, then numeric comparison is taking place.

You can see the difference in the following two examples.

In the first example numeric comparison is taking place. The values are equal. 01 and 1 are numerically the same.

VAR=1
if [ "$VAR" -eq 01 ]; then
  echo "equal"
fi
output
equal

In this next example we compare the same values but as strings.

#!/bin/bash

VAR=1
if [ "$VAR" = 01 ]; then
  echo "equal"
else
  echo "not equal"
fi
output
not equal

Negation and Boolean Operators

Negation uses ! like a lot of other languages to invert the truth value of an expression.

if ! true; then #(1)
  echo "false"
else
  echo "true"
fi
  1. true is a command. If you type which true at the command prompt you’ll find it. There is also a false command.

output
true

You can combine expressions using boolean operators && and ||.

#!/bin/bash

VAR1=20
VAR2=20
if [ "$VAR1" -gt 10 ] && [ "$VAR2" -gt 10 ]; then
  echo "both $VAR1 and $VAR2 are greater than 10"
fi

&& applies short circuit evaluation. In other words, if the first expression is false then the following expressions are not evaluated. A similar thing happens with ||. In this case, if the first expression is true, then the remaining expressions are not evaluated.