How to Use Test Conditions Within a Bash Script

Bash script in GNU nano on Linux desktop

 Lifewire

The Linux test command compares one element against another, but it is more commonly used in BASH shell scripts as part of conditional statements which control logic and program flow.

A Basic Example

test example

Try these commands in a terminal window.

test 1 -eq 2 && echo "yes" || echo "no"

The above command breaks down follows:

  • test: The command to perform a comparison
  • 1:The first element you are going to compare. In this example, it's the number 1 but it could be any number, or a string within quotes.
  • -eq: The method of comparison. In this case, you are testing whether one value equals another.
  • 2: The element you are comparing the first element against. In this example, it's the number 2.
  • &&: A Linux shortcut to chain commands together, in sequence. The output from the test chains to the commands that follow. A double-ampersand executes when the command that precedes it has an exit status of 0, which is a fancy way of saying that the command didn't fail.
  • echo "yes":The command to run if the comparison succeeds. In this case, all we're doing is asking the echo command to print the word "yes" to standard output, but you could run any command here that would execute if the test result proved true.
  • ||: The opposite, in a way, of &&; the double-pipe only executes if the command that precedes it fails (has an exit status that's not 0).
  • echo "no": The command to run if the comparison fails.

Run from a shell prompt, test does not return a value to the standard output, it merely returns an exit-status code. That's why chaining an echo command is necessary.

test exit status

In essence, the command is comparing 1 to 2 and if they match, the echo "yes" statement is executed which displays "yes" and if they do not match, the echo "no" statement is executed which displays "no."

Comparing Numbers

If you are comparing elements that parse as numbers you can use the following comparison operators:

  • -eq: value 1 equals value 2
  • -ge: value 1 greater or equal to value 2
  • -gt: value 1 greater than value 2
  • -le: value 1 less than or equal to value 2
  • -lt: value 1 less than value 2
  • -ne: value 1 does not equal value 2

Example Tests

test 1 -eq 2 && echo "yes" || echo "no"

(displays "no" to the screen because 1 does not equal 2)

test 1 -ge 2 && echo "yes" || echo "no"

(displays "no" to the screen because 1 is not greater or equal to 2)

test 1 -gt 2 && echo "yes" || echo "no"

(displays "no" to the screen because 1 is not greater than 2)

test 1 -le 2 && echo "yes" || echo "no"

(displays "yes" to the screen because 1 is less than or equal to 2)

test 1 -lt 2 && echo "yes" || echo "no"

(displays "yes" to the screen because 1 is less than or equal to 2)

test 1 -ne 2 && echo "yes" || echo "no"

(displays "yes" to the screen because 1 does not equal 2)

Comparing Text

When you compare elements that parse as strings, use the following comparison operators:

  • =: string 1 matches string 2
  • !=: string 1 does not match string 2
  • -n: the string length is greater than 0
  • -z: the string length equals 0

Examples

test "string1" = "string2" && echo "yes" || echo "no"

(displays "no" to the screen because "string1" does not equal "string2")

test "string1" != "string2" && echo "yes" || echo "no"

(displays "yes" to the screen because "string1" does not equal "string2")

test -n "string1" && echo "yes" || echo "no"

(displays "yes" to the screen because "string1" has a string length greater than zero)

test -z "string1" && echo "yes" || echo "no"

(displays "no" to the screen because "string1" has a string length greater than zero)

Comparing Files

When you compare files, use the following comparison operators:

  • -ef: The files have the same device and inode numbers (are they the same file)
  • -nt: The first file is newer than the second file
  • -ot: The first file is older than the second file
  • -b: The file exists and is block special
  • -c: The file exists and is character special
  • -d: The file exists and is a directory
  • -e: The file exists
  • -f: The file exists and is a regular file
  • -g: The file exists and has the specified group number
  • -G: The file exists and owner by the user's group
  • -h or -L: The file exists and is a symbolic link
  • -k: The file exists and has its sticky bit set
  • -O: The file exists you are the owner
  • -p: The file exists and is a named pipe
  • -r: The file exists and is readable
  • -s: The file exists and has a size greater than zero
  • -S: The file exists and is a socket
  • -t: The file descriptor is opened on a terminal
  • -u: The file exists and the set-user-id bit is set
  • -w: The file exists and is writable
  • -x: The file exists and is executable

Examples

test /path/to/file1 -nt /path/to/file2 && echo "yes"

(If file1 is newer than file2 then the word "yes" will be displayed)

test -e /path/to/file1 && echo "yes"

(if file1 exists the word "yes" will be displayed)

test -O /path/to/file1 && echo "yes"

(if you own file1 then the word "yes" is displayed")

Block special: The file is a block device which means that data is read in blocks of bytes. These are generally device files such as hard drives.

Character special: The file is acted upon immediately when you write to it and is commonly a device such as a serial port

Comparing Multiple Conditions

Thus far, everything has been comparing one thing against another, but what if you want to compare two conditions?

For example, if an animal has four legs and goes "moo," it is probably a cow. Simply checking for four legs doesn't guarantee that you have a cow, but checking the sound it makes surely does.​

To test both conditions at once, use the following statement:

test 4 -eq 4 -a "moo" = "moo" && echo "it is a cow" || echo "it is not a cow"

The key part here is the -a flag, which stands for and.

There is a better and more commonly used way of performing the same test and that is as follows:

test 4 -eq 4 && test "moo" = "moo" && echo "it is a cow" || echo "it is not a cow"

Follow the branches!

The branching of the test command is significant. If the first test (4 = 4) fails, the test command terminates with a non-zero exit code. Thus, we jump to the double-pipe symbol and "it is not a cow" prints to standard output. However, if the first test succeeds and thus test results in an exit code of 0, then we jump to the first double-ampersand. That next statement is another test condition!

If the second test fails, again, we jump to the double-pipe and proceed from there. If, however, the second test succeeds, we jump to the second double-ampersand statement, which in this example merely echoes "it is a cow" to standard output and then terminates back to the shell prompt.

Another test compares two statements and if either is true, output a string. For example, to check that a file named "file1.txt" exists or a file called "file1.doc" exists, you can use the following command:

test -e file1.txt -o -e file1.doc && echo "file1 exists" || echo "file1 does not exist"

The key part here is the -o which stands for or.

There is a better and more commonly used way of performing the same test and that is as follows:

test -e file1.txt || test -e file1.doc && echo "file1 exists" || echo "file1 does not exist"

Eliminating the Test Keyword

You don't actually need to use the word test to perform the comparison. All you have to do is enclose the statement in square brackets as follows:

[ -e file1.txt ] && echo "file1 exists" || echo "file1 does not exist"

The [ and ] basically means the same as test.

Now you know this you can improve on comparing multiple conditions as follows:

[ 4 -eq 4 ] && [ "moo" = "moo" ] && echo "it is a cow" || echo "it is not a cow"

[ -e file1.txt ] || [ -e file1.doc ] && echo "file1 exists" || echo "file1 does not exist"

Summary

The test command is more useful in scripts because you can test the value of one variable against another and control program flow. On the command line, use it to test whether a file exists or not.