Bash test builtin command

Updated: 02/01/2021 by Computer Hope
test command

On Unix-like operating systems, test is a builtin command of the Bash shell that tests file attributes, and perform string and arithmetic comparisons.

Description

test provides no output, but returns an exit status of 0 for "true" (test successful) and 1 for "false" (test failed).

The test command is frequently used as part of a conditional expression. For instance, the following statement says, "If 4 is greater than 5, output yes, otherwise output no."

num=4; if (test $num -gt 5); then echo "yes"; else echo "no"; fi
no

The following statement says, "If 6 is greater than 5, output yes, otherwise output no."

num=6; if (test $num -gt 5); then echo "yes"; else echo "no"; fi
yes

The test command may also be expressed with single brackets [ ... ], as long as they are separated from all other arguments with whitespace. For example, the following statement checks that the system file /etc/passwd exists, and if not, outputs "uh-oh."

file="/etc/passwd"; if [ -e $file ]; then echo "whew"; else echo "uh-oh"; fi
whew

Syntax

File tests:

test [-a] [-b] [-c] [-d] [-e] [-f] [-g] [-h] [-L] [-k] [-p] [-r] [-s] [-S]
     [-u] [-w] [-x] [-O] [-G] [-N] [file]
test -t fd
test file1 {-nt | -ot | -ef} file2

String tests:

test [-n | -z] string
test string1 {= | != | < | >} string2

Shell options and variables:

test -o option
test {-v | -R} var

Simple logic (test if values are null):

test [!] expr
test expr1 {-a | -o} expr2

Numerical comparison (for integer values only; bash doesn't do floating point math):

test arg1 {-eq | -ne | -lt | -le | -gt | -ge} arg2

Options

The test builtin command takes the following options.

-a file Returns true if file exists. Does the same as -e. Both are included for compatibility reasons with legacy versions of Unix.
-b file Returns true if file is "block-special." Block-special files are similar to regular files, but are stored on block devices — special areas on the storage device that are written or read one block (sector) at a time.
-c file Returns true if file is "character-special." Character-special files are written or read byte-by-byte (one character at a time), immediately, to a special device. For example, /dev/urandom is a character-special file.
-d file Returns true if file is a directory.
-e file Returns true if file exists. Does the same as -a. Both are included for compatibility reasons with legacy versions of Unix.
-f file Returns true if file exists, and is a regular file.
-g file Returns true if file has the setgid bit set.
-h file Returns true if file is a symbolic link. Does the same as -L. Both are included for compatibility reasons with legacy versions of Unix.
-L file Returns true if file is a symbolic link. Does the same as -h. Both are included for compatibility reasons with legacy versions of Unix.
-k file Returns true if file has its sticky bit set.
-p file Returns true if the file is a named pipe, e.g., as created with the command mkfifo.
-r file Returns true if file is readable by the user running test.
-s file Returns true if file exists, and is not empty.
-S file Returns true if file is a socket.
-t fd Returns true if file descriptor fd is opened on a terminal.
-u file Returns true if file has the setuid bit set.
-w file Returns true if the user running test has write permission to file, i.e., make changes to it.
-x file Returns true if file is executable by the user running test.
-O file Returns true if file is owned by the user running test.
-G file Returns true if file is owned by the group of the user running test.
-N file Returns true if file was modified since the last time it was read.
file1 -nt file2 Returns true if file1 is newer (has a newer modification date/time) than file2.
file1 -ot file2 Returns true if file1 is older (has an older modification date/time) than file2.
file1 -ef file2 Returns true if file1 is a hard link to file2.
test [-n] string Returns true if string is not empty. Operates the same with or without -n.

For example, if mystr="", then test "$mystr" and test -n "$mystr" would both be false. If mystr="Not empty", then test "$mystr" and test -n "$mystr" would both be true.
-z string Returns true if string string is empty, i.e., "".
string1 = string2 Returns true if string1 and string2 are equal, i.e., contain the same characters.
string1 != string2 Returns true if string1 and string2 are not equal.
string1 < string2 Returns true if string1 sorts before string2 lexicographically, according to ASCII numbering, based on the first character of the string. For instance, test "Apple" < "Banana" is true, but test "Apple" < "banana" is false, because all lowercase letters have a lower ASCII number than their uppercase counterparts.

Tip: Enclose any variable names in double quotes to protect whitespace. Also, escape the less than symbol with a backslash to prevent bash from interpreting as a redirection operator. For instance, use test "$str1" \< "$str2" instead of test $str1 < $str2. The latter command will try to read from a file whose name is the value of variable str2. For more information, see redirection in bash.
string1 > string2 Returns true if string1 sorts after string2 lexicographically, according to the ASCII numbering. As noted above, use test "$str1" \> "$str2" instead of test $str1 > $str2. The latter command creates or overwrites a file whose name is the value of variable str2.
-o option Returns true if the shell option opt is enabled.
-v var Returns true if the shell variable var is set.
-R var Returns true if the shell variable var is set, and is a name reference. (It's possible this refers to an indirect reference, as described in Parameter expansion in bash.)
! expr Returns true if and only if the expression expr is null.
expr1 -a expr2 Returns true if expressions expr1 and expr2 are both not null.
expr1 -o expr2 Returns true if either of the expressions expr1 or expr2 are not null.
arg1 -eq arg2 True if argument arg1 equals arg2.
arg1 -ne arg2 True if argument arg1 is not equal to arg2.
arg1 -lt arg2 True if numeric value arg1 is less than arg2.
arg1 -le arg2 True if numeric value arg1 is less than or equal to arg2.
arg1 -gt arg2 True if numeric value arg1 is greater than arg2.
arg1 -ge arg2 True if numeric value arg1 is greater than or equal to arg2.

Notes

All arguments to test must be separated by a space, including all operators.

The < and > operators are lexicographical comparisons, based on ASCII numbering. They are not numerical operators (instead, use -lt, -gt, etc. for comparing numbers).

The precise behavior of test, depending on the number of arguments provided, is as follows:

# args test behavior
0 Always return false.
1 Return true, if and only if the expression is not null.
2 If the first argument is !, return true if and only if the expression is null.

If the first argument is one of the other unary operators (-a, -b, etc.), return true if and only if the unary test of the second argument is true.

If the first argument is not an unary operator, return false.
3 The following conditions are applied in the order listed.

If the second argument is one of the binary conditional operators listed above, the result is the binary test using the first and third arguments as operands. Binary conditional operators are those which take two operands, e.g., -nt, -eq, <, etc.

The -a and -o operators are considered binary operators when there are three arguments.

If the first argument is !, the value is the negation of the two-argument test using the second and third arguments.

If the first argument is exactly ( and the third argument is exactly ), the result is the one-argument test of the second argument. In other words, ( expr ) returns the value of expr. This special case exists as a way to override the normal precedence of operations.

Otherwise, the expression is false.
4 If the first argument is !, the result is the negation of the three-argument expression composed of the remaining arguments.

Otherwise, the expression is parsed and evaluated according to precedence using the rules listed above.
5+ The expression is parsed and evaluated according to precedence using the rules listed above.

Exit status

0 for true, 1 for false. Anything greater than 1 indicates an error or malformed command.

Examples

test

This command returns 1 for false, because it has no arguments to test. (See notes above for how test behaves with various numbers of arguments.) This is good, because the only time test should ever run with no arguments is when something has gone wrong in your script or command.

To confirm that test returned false, we'll check the value of the special shell variable ?, which contains the exit status of the previous command executed.

echo $?
1

Here are a few more examples.

if test false; then 
  echo "Test always returns true for only one argument, unless it is null."; 
fi
Test always returns true for only one argument, unless it is null.
[ false ]; echo $?      # always true for one argument if not null
0
[ true ]; echo $?       # same as previous command
0
test -e /sys; echo $?   # true if file or directory exists
0
test -e /does-not-exist; echo $?
1
test -c /dev/uinput; echo $?   # true for character-special devices
0
if test -d /home; then echo "/home is a directory"; fi
/home is a directory
test -f /etc/shadow; echo $?   # true for regular files
0
test -f /etc; echo $?          # false for directories
1
test -h /dev/stdin; echo $?    # true for symbolic links
0
pn="MyPipe"; mkfifo "$pn"; test -p mypipe; 
if [ $? -eq 0 ]; then 
  echo "$pn is a named pipe"; 
fi
MyPipe is a named pipe
test -r /etc/motd; echo $?   # true if file is readable by current user
0
file="/etc/passwd"; 
if [ -s "$file" ]; then 
  echo "$file exists, and is not empty"; 
fi
/etc/passwd exists, and is not empty
touch newfile; if [ -O newfile ]; then echo "I own newfile"; fi
I own newfile
str=""; test -z "$str"; echo $?   # true if variable str is empty string ""
0
str=""; test -n "$str"; echo $?   # true if variable str is not empty string ""
1
str=""; test "$str"; echo $?      # same as above command; -n is optional
1
str="Not empty"; test -z "$str"; echo $?
1
str="Not empty"; test -n "$str"; echo $?
0
str="Not empty"; test "$str"; echo $?
0
if test -x /bin/bash; then echo "/bin/bash is executable"; fi
/bin/bash is executable
str="Match"; if [ "$str" = "Match" ]; then 
  echo "The strings match."; 
else
  echo "The strings do not match.";
fi
The strings match.
str="match"; if [ "$str" = "Match" ]; then 
  echo "The strings match."; 
else
  echo "The strings do not match.";
fi
The strings do not match.
test "Apple" \< "Banana"; echo $?   # true because ASCII 65 (A) < 66 (B)
0
test "apple" \< "Banana"; echo $?   # false because ASCII 97 (a) is not < 66 (B)
1
test 5 -gt 6; echo $?       # false because 5 is not greater than 6
1
test 6 -gt 5; echo $?       # true
0
test "6" -gt "5"; echo $?   # quoted numbers are properly compared
0
test 5.5 -gt 5.4; echo $?   # error: bash doesn't do floating point math
bash: test: 5.5: integer expression expected
2

df — View used and available disk space.
free — View used and available memory.