test
Evaluate conditional expressions
TLDR
Test if a given variable is equal to a given string
Test if a given variable is empty ([z]ero length)
Test if a [f]ile exists
Test if a [d]irectory does not exist
If A is true, then do B, or C in the case of an error (notice that C may run even if A fails)
Use test in a conditional statement
SYNOPSIS
test EXPRESSION
[ EXPRESSION ]
PARAMETERS
-b FILE
True if FILE exists and is a block special file.
-c FILE
True if 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 (same as -L).
-k FILE
True if FILE exists and its sticky bit is set.
-L FILE
True if FILE exists and is a symbolic link (same as -h).
-p FILE
True if FILE exists and is a named pipe (FIFO).
-r FILE
True if FILE exists and is readable by the current user.
-s FILE
True if FILE exists and has a size greater than zero.
-S FILE
True if FILE exists and is a socket.
-t FD
True if file descriptor FD (default 1) 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 by the current user.
-x FILE
True if FILE exists and is executable by the current user.
-O FILE
True if FILE exists and is owned by the effective user ID.
-G FILE
True if FILE exists and is owned by the effective group ID.
-N FILE
True if FILE exists and has been modified since it was last read.
STRING
True if STRING is not empty.
-z STRING
True if the length of STRING is zero.
-n STRING
True if the length of STRING is non-zero (same as just STRING).
STRING1 = STRING2
True if the strings STRING1 and STRING2 are equal.
STRING1 != STRING2
True if the strings STRING1 and STRING2 are not equal.
INT1 -eq INT2
True if the integers INT1 and INT2 are arithmetically equal.
INT1 -ne INT2
True if the integers INT1 and INT2 are not arithmetically equal.
INT1 -gt INT2
True if the integer INT1 is arithmetically greater than INT2.
INT1 -ge INT2
True if the integer INT1 is arithmetically greater than or equal to INT2.
INT1 -lt INT2
True if the integer INT1 is arithmetically less than INT2.
INT1 -le INT2
True if the integer INT1 is arithmetically less than or equal to INT2.
! EXPRESSION
True if EXPRESSION is false (logical negation).
EXP1 -a EXP2
True if both EXP1 and EXP2 are true (logical AND).
EXP1 -o EXP2
True if either EXP1 or EXP2 is true (logical OR).
( EXPRESSION )
Evaluates EXPRESSION as a single unit; parentheses must be escaped or quoted for the shell.
DESCRIPTION
The test command evaluates an EXPRESSION and returns an exit status of 0 (true) if the EXPRESSION is true, and 1 (false) if it is false. It is commonly used in shell scripts within if, while, or until statements to control program flow based on conditions. The test command is often invoked using its alias [ (which requires a closing ] as the last argument).
It supports various types of tests, including checking file attributes (e.g., if a file exists, is a directory, or is readable), comparing strings, and comparing numeric values. The command itself does not produce any output; its result is solely determined by its exit status. Understanding test is fundamental for writing robust and dynamic shell scripts that can make decisions based on different conditions in the environment. It is a POSIX standard utility, making it widely available across Unix-like systems.
CAVEATS
The test command, especially when used as [, requires careful attention to spacing. Each operator and argument must be a separate word, meaning they need to be separated by spaces. For example, [ "$VAR" = "value" ] is correct, while ["$VAR"="value"] is not.
String arguments should almost always be quoted (e.g., "$VAR") to prevent issues with empty strings or strings containing spaces/special characters, which could lead to syntax errors or unexpected evaluation results. Numeric comparisons (e.g., -eq) only work with integers. Portability can be an issue with some less common operators or specific behaviors, as different shells might have slightly varied implementations, though the core POSIX standard operators are reliable.
EXIT STATUS
The test command does not produce output to standard output or standard error. Its only result is its exit status: 0 (true) if the EXPRESSION evaluates to true, and 1 (false) if it evaluates to false. This exit status is then used by the shell to control flow in if, while, and until statements.
SHELL BUILT-IN
While test exists as an executable in /usr/bin/test (or similar), it is almost always implemented as a built-in command within modern shells like Bash, Zsh, and Dash. This makes its execution significantly faster as it avoids the overhead of launching a new process, which is crucial for efficient script execution.
STRING QUOTING
When using test with string variables, it is a common best practice to quote the variables (e.g., [ -f "$FILE" ] or [ "$VAR" = "hello" ]). This prevents unexpected behavior if the variable is empty or contains spaces, tabs, or other special characters, which could otherwise be interpreted as separate arguments to test.
HISTORY
The test command has been a fundamental part of Unix-like operating systems since their early development. It was included in the Seventh Edition Unix (V7) in 1979. Its alternative name, [, was introduced later, primarily for syntactic sugar in shell scripting to make conditional statements resemble more conventional programming language constructs. Over time, test became a core utility specified by the POSIX standard, ensuring its widespread availability and consistent behavior across various Unix and Linux distributions. Many modern shells implement test as a built-in command for performance reasons, avoiding the overhead of spawning an external process.