2.5 Conditionals
In most computing contexts, we very often must rely on the system being able to make decisions for us without requiring the user to step in. This is where the concept of conditionals comes into play.
Conditionals are a common programming construct, and many are familiar with the syntax in C-like languages. However, in the case of Bash, the way this is implemented differs by a fair amount. The language provides two distinct ways of doing comparisons, with slight difference depending on use-case.
When it comes to files, strings, and numbers, you have a number of actions you can perform according to the GNU Documentation[1]. The most common/useful operations have been marked in bold.
File Operators
Condition | Description |
---|---|
-a <file> | True if the file exists. |
-b <file> | True if the file exists and is a block special file. |
-c <file> | True if the file exists and is a character special file. |
-d <file> | True if file exists and is a directory. |
-e <file> | True if file exists. |
-f <file> | True if file exists and is a regular file. |
-g <file> | True if file exists and its set-group-id bit is set. |
-h <file> | True if file exists and is a symbolic link. |
-k <file> | True if file exists and its "sticky" bit is set. |
-p <file> | True if file exists and is a named pipe (FIFO). |
-r <file> | True if file exists and is readable. |
-s <file> | True if file exists and has a size greater than zero. |
-t <file> | True if file descriptor fd is open and refers to a terminal. |
-u <file> | True if file exists and its set-user-id bit is set. |
-w <file> | True if file exists and is writable. |
-x <file> | True if file exists and is executable. |
-G <file> | True if file exists and is owned by the effective group id. |
-L <file> | True if file exists and is a symbolic link. |
-N <file> | True if file exists and has been modified since it was last read. |
-O <file> | True if file exists and is owned by the effective user id. |
-S <file> | True if file exists and is a socket. |
<file1> -ef <file2> | True if file1 and file2 refer to the same device and inode numbers. |
<file1> -nt <file2> | True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not. |
<file1> -ot <file2> | True if file1 is older than file2, or if file2 exists and file1 does not. |
String Operators
Condition | Description |
---|---|
-z <string> | True if the length of string is zero. |
-n <string> | True if the length of string is non-zero. |
<string> | True if the length of string is non-zero. |
<string1> == <string2> | True if the strings are equal. |
<string1> != <string2> | True if the strings are not equal. |
<string1> < <string2> | True if string1 sorts before string2 lexicographically. |
<string1> > <string2> |
True if string1 sorts after string2 lexicographically. |
Arithmetic Operators
While most programming languages embrace some of the operators in the above section for their general comparisons. Bash does not use those operators for performing arithmetic checks. Instead, it is necessary to perform such checks using the following syntax options.
Condition | Description |
---|---|
<arg1> -eq <arg2> | If the first number is equal to the second number. |
<arg1> -ne <arg2> | If the first number is not equal to the second number. |
<arg1> -lt <arg2> | If the first number is less than the second number. |
<arg1> -le <arg2> | If the first number is less than or equal to the second number. |
<arg1> -gt <arg2> | If the first number is greater than the second number. |
<arg1> -ge <arg2> | If the first number is greater than or equal to the second number. |
If / Else If / Else Statements
Conditionals are often used in control statements to alter the flow of scripts. If statements are one form of control statement which can be used to execute statements only under specific circumstances. Unlike other programming languages however, Bash implements the syntax for these statements in a fairly unique manner.
Simple If statement:
example="hello"
if [ $example != "world!" ]; then
echo "Condition passed!"
fi
if [ $example == "foo" ]; then
echo "This will not execute"
fi
If/Else If Statement:
example="hello"
# Will execute the second branch
if [ $example == "world!" ]; then
echo "Branch A"
elif [ $example == "hello" ]; then
echo "Branch B"
fi
If / Else If / Else Statement:
example="hello"
# Will execute the last branch
if [ $example == "world!" ]; then
echo "Branch A"
elif [ $example != "hello" ]; then
echo "Branch B"
else
echo "No matching case!"
fi
The if
statement is one of several statements which must be terminated by the same keyword in opposite order. You can insert extra else if
or else
statements into the block, but it must otherwise be terminated by a matching fi
keyword.
Further Reading
If statements are not the only form of control flow components available to us in Bash, we also have the ability to use case
statements to approach the problems from a different perspective. If you would like to read up on this, I encourage you to look through 3.3 Pattern Matching.