Tests in bash
Tests are fundamental feature in bash scripting. However, tests in bash are not the same as test in some application – they do not check if your script works correctly, it’s a way to write an expressions that can be true or false.
$ [ 1 = 0 ] $ echo $? 1 // false $ [ 1 = 1 ] $ echo $? 0 // true
$? variable is a special variable that gives you a number telling you result of the last-executed command. If it returned true, the number will (usually) be ‘0’. If it didn’t, the number will (usually) not be ‘0’.
Unlike in many programming languages, there is no difference in using single equal sign to double.
$ [ 1 = 1 ] $ echo $? 0 // true $ [ 1 == 1 ] $ echo $? 0 // true
Space required
Hence [
and ]
are builtins, the space is required after them. The [
is the separate command, and bash spacing is the way how bash determines where the one command ends and another begins.
$ [1 == 1] bash: [1: command not found $ echo $? 127 $ [ 1 == 1 ] $ echo $? 0 // true
[ vs [[
The difference between them is very subtle, try below code to find out what it actually is.
$ unset DOESNOTEXIST $ [ ${DOESNOTEXIST} = '' ] bash: [: =: unary operator expected $ echo $? 2 // misuse of builtin $ [[ ${DOESNOTEXIST} = '' ]] $ echo $? 0
First command with single [
evaluates command to [ = '' ]
, thus error is thrown. Command with [[
transforms empty variable to empty string [ '' = '' ]
and the test is true.
In practice you should use [[ until there is a good reason not to. More on the differences between these two can be found here.
Unary operators
$ echo $PWD /home/root $ [[ -z $PWD ]] $ echo $? 1 // false
-z
returns true only if the argument is an empty string. Interestingly, this test will pass even we provide empty variable:
$ echo $FAKE $ [[ -z $PWD ]] $ echo $? 0 // TRUE!
Another most common unary operators are -a
and -d
.
$ touch file $ [[ -a file ]] $ echo $? 0 // TRUE = file exists $ [[ -a second_file ]] $ echo $? 1 // FALSE = file does not exist
$ mkdir folder $ [[ -d folder ]] $ echo $? 0 // TRUE = folder exists $ [[ -a second_folder ]] $ echo $? 1 // FALSE = folder does not exist
Binary operators
$ [[ 10 -lt 2 ]] // less than $ [[ 10 -gt 1 ]] // greater than $ [[ 10 -eq 1 ]] // equals $ [[ 10 -ne 1 ]] // not equals
If statements
In the end, we are going to use tests very frequently in the if
statements.
--- script.sh --- #!/bin/bash if [[ 10 -lt 5 ]]; then echo 'if block' elif [[ 10 -gt 4 ]]; then echo 'elif block' else echo 'else block' fi $ ./script.sh elif block