On this page
In Bash scripting, the test
command is a fundamental tool used to evaluate conditions and make decisions based on those conditions. Whether you're checking if a file exists, comparing strings, or validating numeric values, the test
command plays a crucial role in controlling the flow of your script. In this article, you'll learn how to use the test
command effectively, with practical examples to help you apply it in real-world scenarios.
What is the test
Command?
The test
command in Bash is used to evaluate expressions and return a status code. A status code of 0
indicates that the expression is true, while a non-zero status code indicates false. The test
command can be used in three different syntaxes, each with its own advantages:
Using the test
Keyword
The most straightforward way to use test
is by directly invoking the test
command:
test EXPRESSION
FILE=/etc/app/config
if test -f "$FILE"; then
echo "$FILE exists."
fi
This form is available in all POSIX-compliant shells and is the most portable across different Unix-like systems. It evaluates the given expression and returns a status code indicating whether the expression is true (0
) or false (non-zero).
Using Square Brackets [ ]
A more common and readable shorthand for the test
command is to use single square brackets:
[ EXPRESSION ]
if [ -f "$FILE" ]; then
echo "The file exists."
fi
This form is functionally identical to using the test
keyword but is often preferred for its simplicity and readability. It’s widely supported and typically used in conditional statements within Bash scripts.
Using Double Square Brackets [[ ]]
Double square brackets [[ ]]
are an extended version of the test
command available in Bash and some other modern shells like Zsh and Ksh. This syntax provides additional features and more flexibility compared to single square brackets:
[[ EXPRESSION ]]
Key Features of [[ ]]
:
- No Word Splitting or Filename Expansion: Because
[[ ]]
is built into the shell and doesn’t have legacy requirements, you don’t need to worry about word splitting based on theIFS
variable. This means that variables evaluating to strings with spaces won’t be split unexpectedly, so you don’t need to put variables in double quotes as you would with single brackets:
String Comparison: [[ ]]
can also handle more advanced string comparison, including lexicographical comparisons:
if [[ "$STRING1" > "$STRING2" ]]; then
echo "$STRING1 is greater than $STRING2"
fi
Logical Operators: The &&
(AND) and ||
(OR) operators are built into the [[ ]]
syntax, allowing you to combine multiple conditions more cleanly without needing to nest them.
if [[ -f "$FILE" && -r "$FILE" ]]; then
echo "The file exists and is readable."
fi
Pattern Matching with =~
: Unlike single square brackets, [[ ]]
allows you to use regular expressions for pattern matching. For example:
if [[ $STRING =~ ^[A-Za-z]+$ ]]; then
echo "The string contains only letters."
fi
This example checks if the string contains only letters using a regular expression.
This additional functionality makes [[ ]]
more powerful and flexible, especially for complex conditions in scripts. However, it’s important to note that [[ ]]
is not POSIX-compliant and may not be available in all Unix-like environments, so it’s best used when you’re certain that your script will be run in a Bash or similar modern shell environment.
To learn more about the difference between test, [ and [[ check out this article.
Using the test
Command: Practical Examples
Now that you know what the test
command is, let's look at some examples of using it in practice. Throughout these examples, we’ll use the [ ]
syntax, which is commonly used and easy to read.
Checking File Existence
One of the most common uses of the test
command is to check whether a file or directory exists. This is particularly useful when your script depends on certain files being present.
Check if a directory exists:The -d
flag is used to verify that the specified path is a directory.
DIRECTORY=/etc
if [ -d "$DIRECTORY" ]; then
echo "$DIRECTORY is a directory."
fi
Check if a regular file exists:The -f
flag specifically checks for regular files, excluding directories and other types of files.
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
Check if a file exists:The -e
flag checks if the file exists, regardless of its type (regular file, directory, socket, etc.).
FILE=/etc/passwd
if [ -e "$FILE" ]; then
echo "$FILE exists."
fi
Using Logical Operators
The test
command can be combined with logical operators to evaluate multiple conditions, making it more versatile in your scripts.
Negation:The !
operator negates the condition, allowing you to check if a file does not exist:
if [ ! -f /etc/nonexistent ]; then
echo "The file does not exist."
fi
OR condition:To check whether at least one of the specified files exists, use the ||
operator:
if [ -f /etc/passwd ] || [ -f /etc/shadow ]; then
echo "At least one file exists."
fi
AND condition:To check whether both files exist, you can use the &&
operator:
if [ -f /etc/passwd ] && [ -f /etc/hosts ]; then
echo "Both files exist."
fi
Additional Practical Examples
Here are a few more examples that demonstrate how the test
command can be used for various checks:
Check if a file has a non-zero size:This is useful for verifying that a file is not empty before proceeding with operations that depend on its content:
if [ -s "$FILE" ]; then
echo "$FILE has a non-zero size."
fi
Check if a symbolic link exists:The -L
flag checks if the specified path is a symbolic link:
LINK=/usr/bin/python
if [ -L "$LINK" ]; then
echo "$LINK is a symbolic link."
fi
Check if a file is readable and writable:This ensures that the file can be both read and modified by the script:
if [ -r "$FILE" ] && [ -w "$FILE" ]; then
echo "$FILE is readable and writable."
fi
Ensuring Configuration Files Are Present
Imagine you have a script that depends on certain configuration files. You can use the test
command to ensure these files exist before proceeding:
CONFIG=/etc/myapp/config.cfg
if [ -f "$CONFIG" ]; then
echo "Configuration file found, proceeding with setup..."
else
echo "Error: Configuration file not found!"
exit 1
fi
If the configuration file does not exist, the script will terminate with an error message.
File Test Operators
The test
command provides a variety of operators that allow you to check specific attributes of files. These operators help you determine not just the existence of a file, but also its type, permissions, and other characteristics. Here’s a list of the most commonly used file test operators:
-b FILE
: Returns true if the file exists and is a special block device (e.g., a disk).-c FILE
: Returns true if the file exists and is a special character device (e.g., a terminal or printer).-d FILE
: Returns true if the file exists and is a directory.-e FILE
: Returns true if the file exists, regardless of its type (regular file, directory, socket, etc.).-f FILE
: Returns true if the file exists and is a regular file (not a directory or device).-G FILE
: Returns true if the file exists and has the same group ownership as the user running the command.-h FILE
orL FILE
: Returns true if the file exists and is a symbolic link.-g FILE
: Returns true if the file exists and has the set-group-ID (sgid) bit set.-k FILE
: Returns true if the file exists and has the sticky bit set.-O FILE
: Returns true if the file exists and is owned by the user running the command.-p FILE
: Returns true if the file exists and is a named pipe (FIFO).-r FILE
: Returns true if the file exists and is readable by the user running the command.-S FILE
: Returns true if the file exists and is a socket.-s FILE
: Returns true if the file exists and has a non-zero size (i.e., it is not empty).-u FILE
: Returns true if the file exists and has the set-user-ID (suid) bit set.-w FILE
: Returns true if the file exists and is writable by the user running the command.-x FILE
: Returns true if the file exists and is executable by the user running the command.
Conclusion
The test
command plays a crucial role in Bash scripting, enabling you to evaluate conditions and make decisions within your scripts. By understanding how to use it to check file existence, compare strings, and assess other conditions, you can write scripts that are both dependable and adaptable to different scenarios.