How to test Shell Script Inputs

To ensure that scripts are not easily derailed by unexpected conditions, it is good practice for script authors to not make assumptions regarding inputs, such as command-line arguments, user inputs, command substitutions, variable expansions, filename expansions, etc. Integrity checking can be performed by using Bash’s test feature. Tests can be performed using Bash’s test command syntax, [ TESTEXPRESSION ]. They can also be performed using Bash’s newer extended test command syntax, [[ TESTEXPRESSION ]], which has been available since Bash version 2.02.

Like all commands, the test command produces an exit code upon completion, which is stored as the value $?. To see the conclusion of a test, simply display the value of $? immediately following the execution of the test command. Once again, an exit status value of 0 indicates the test succeeded, while nonzero values indicate the test failed.

Performing comparison tests

Comparison test expressions make use of binary comparison operators. These operators expect two objects, one on each side of the operator, and evaluate the two for equality and inequality. Bash uses a different set of operators for string and numeric comparisons and uses the following syntax format:

[ [ITEM1] [BINARY COMPARISON OPERATOR] [ITEM2] ]

Bash’s numeric comparison is limited to integer comparison. The following list of binary comparison operators is used in Bash for integer comparison.

OPERATOR MEANING EXAMPLE
-eq is equal to [ “$a” -eq “$b” ]
-ne is not equal to [ “$a” -ne “$b” ]
-gt is greater than [ “$a” -gt “$b” ]
-ge is greater than or equal to [ “$a” -ge “$b” ]
-lt is less than [ “$a” -lt “$b” ]
-le is less than or equal to [ “$a” -le “$b” ]

The following examples demonstrate the use of Bash’s numeric comparison operators.

$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -ne 1 ]; echo $?
1
$ [ 8 -gt 2 ]; echo $?
0
$ [ 2 -ge 2 ]; echo $?
0
$ [ 2 -lt 2 ]; echo $?
1
$ [ 1 -lt 2 ]; echo $?
0

Bash’s string comparison uses the following binary operators.

OPERATOR MEANING EXAMPLE
= is equal to [ “$a” = “$b” ]
== is equal to [ “$a” == “$b” ]
!= is not equal to [ “$a” != “$b” ]

The following examples demonstrate the use of Bash’s string comparison operators.

$ [ abc = abc ]; echo $?
0
$ [ abc == def ]; echo $?
1
$ [ abc != def ]; echo $?
0

Bash also has a few unary operators available for string evaluation. Unary operators evaluate just one item using the following format.

[ [UNARY OPERATOR] [ITEM] ]

The following table shows Bash’s unary operators for string evaluation.

OPERATOR MEANING EXAMPLE
-z string is zero length (null) [ -z “$a” ]
-n string is not null [ -n “$a” ]

The following examples demonstrate the use of Bash’s string unary operators.

$ STRING=''; [ -z "$STRING" ]; echo $?
0

$ STRING='abc'; [ -n "$STRING" ]; echo $?
0

Testing files and directories

Bash’s string and binary operators allow users to implement the good practice of not assuming the integrity of inputs to a shell script. The same caution should be utilized when scripts interact with external entities, such as files and directories. Bash offers a large number of test operators for this purpose, as listed in the following table.

OPERATOR MEANING EXAMPLE
-b file exists and is block special [ -b ]
-c file exists and is character special [ -c ]
-d file exists and is a directory [ -d ]
-e file exists [ -e ]
-f file is a regular file [ -f ]
-L file exists and is a symbolic link [ -L ]
-r file exists and read permission is granted [ -r ]
-s file exists and has a size greater than zero [ -s ]
-w file exists and write permission is granted [ -w ]
-x file exists and execute (or search) permission is granted [ -x ]

Bash also offers a few binary comparison operators for performing file comparison. These operators are defined in the following table.

OPERATOR MEANING EXAMPLE
-ef FILE1 has the same device and inode number as FILE2 [ -ef ]
-nt FILE1 has newer modification date than FILE2 [ -nt ]
-ot FILE1 has older modification date than FILE2 [ -ot ]

Logical AND, OR operators

Situations may arise where it may be useful to test more than one condition. Bash’s logical AND operator, &&, allows users to perform a compound condition test to see if both of two conditions are true. On the other hand, Bash’s logical OR operator, ||, allows users to test whether one of two conditions are true. The following examples demonstrate the use of Bash’s logical AND and OR operators.

$ [ 2 -gt 1 ] && [ 1 -gt 0 ]; echo $?
0

$ [ 2 -gt 1 ] && [ 1 -gt 2 ]; echo $?
1

$ [ 2 -gt 1 ] || [ 1 -gt 2 ]; echo $?
0

$ [ 0 -gt 1 ] || [ 1 -gt 2 ]; echo $?
1