The bash test command, also known as the [ command or test command, is a simple yet extremely versatile tool for evaluating expressions in Linux shell scripts. Despite its unassuming appearance, mastering the test command opens up endless possibilities for controlling program flow and making decisions in your scripts.
In this comprehensive guide, we‘ll explore everything you need to know to harness the power of the test command, from basic syntax and simple examples to advanced use cases. Whether you‘re a beginning or experienced Linux scripter, read on to step up your scripting game!
Test Command Syntax
The test command syntax is:
test EXPRESSION
Or:
[ EXPRESSION ]
Where EXPRESSION can be any expression that evaluates to true or false. For example:
[ $a -eq $b ]
Which tests if $a is equal to $b.
The test command returns an exit status of 0 if EXPRESSION evaluates to true, or 1 if EXPRESSION evaluates to false. This exit status is assigned to the $? variable.
Here is a simple example:
$ test 1 -eq 1 && echo "True" || echo "False"
True
$ echo $?
0
The test command allows you to compare strings, integers, files and more. We‘ll cover the different expression types later on.
First, a quick note on good practice – it‘s recommended to put test expressions in square brackets rather than calling test directly. The rest of this guide will follow that convention for improved readability and compatibility.
Comparing Integers
Comparing integers is one of the most common uses for the test command.
Here is the syntax to compare two integers:
[ integer1 -OP integer2 ]
Where -OP is the comparison operator, which can be:
-eq– Equal to-ne– Not equal to-gt– Greater than-ge– Greater than or equal-lt– Less than-le– Less than or equal
Let‘s try a few simple examples:
# 5 equals 5
[ 5 -eq 5 ] && echo "true" || echo "false"
true
# 5 does not equal 4
[ 5 -ne 4 ] && echo "true" || echo "false"
true
# 5 is greater than 2
[ 5 -gt 2 ] && echo "true" || echo "false"
true
We can even use variables instead of direct values:
a=5
b=2
[ $a -gt $b ] && echo "true" || echo "false"
true
Getting comfortable with integer comparisons allows for straightforward conditional logic in scripts.
Comparing Strings
Besides numbers, shell scripts often need to work with text and strings. Conveniently, test provides operators for comparing strings too.
Here is the basic string comparison syntax:
[ string1 OP string2 ]
The comparison operators (OP) for strings:
=– Equal to!=– Not equal to-z– String is empty (zero length)-n– String length is not zero
Let‘s try out some string comparisons:
[ "hello" = "hello" ] && echo "true" || echo "false"
true
[ "hello" != "world" ] && echo "true" || echo "false"
true
my_var="hello"
[ -n "$my_var" ] && echo "true" || echo "false"
true
empty_var=""
[ -z "$empty_var" ] && echo "true" || echo "false"
true
The ability to check if a string variable is empty or compare values allows for easy processing of user input, API responses, and more.
Checking File Attributes
In system administration, scripting often involves inspecting and manipulating files and directories.
The test command provides a full suite of operators to evaluate file attributes, check permissions, compare modification times, and more.
Here are some examples of useful file-related expressions:
Check if file exists:
[ -e "/path/to/file" ]
Check if path exists and is a directory:
[ -d "/home/myuser" ]
Check for write permissions:
[ -w "my_config.txt" ]
Check if file1 is newer than file2:
[ file1 -nt file2 ]
There are over a dozen file attribute checks available. See the man page for test or [ for all the possibilities – they give scripts a lot of power for working with the filesystem and files.
Combining Multiple Tests
A major advantage of the test command is the ability to combine checks using Boolean logic. Complex test expressions can be constructed by joining multiple test commands with Bash conditional operators:
&&– Logical AND||– Logical OR
For example:
# User is in sudo group AND uid is not 0
[ groups username | grep ‘\bsudo\b‘ ] && [ "$UID" -ne 0 ]
By chaining test commands in this way, very sophisticated conditional logic can be implemented in scripts.
Using Test Command in Conditional Statements
The most common application for test is in if statements and conditional loops to control program flow.
Here is a simple example with if/else logic:
if [ "$(whoami)" = "root" ]; then
echo "You are root"
else
echo "You are NOT root"
fi
We can also construct conditional loops:
# While not root, print message
while ! [ "$(whoami)" = "root" ]; do
echo "Run me as root!"
sleep 5
done
When you understand all the expression possibilities with test/[, you can build quite advanced decision making into scripts.
Additional Test Command Operators
The test command has some additional operators to further enhance script capability:
File Type Checks
Test if a file exists and is a:
- Block device:
-b FILE - Character device:
-c FILE - Socket:
-S FILE - Symbolic link:
-L FILE
Logical Operators
Combine multiple test commands with:
- AND logical operator:
-a - OR logical operator:
-o
Arithmetic Binary Operators
Allow math directly in test command:
+Addition-Subtraction*Multiplication/Division
Other Checks
- File has SUID set:
-u FILE - File has SGID set:
-g FILE - FD is open on file:
-p FD
See full docs for even more!
Test Command vs Double Bracket [[ ]]
Bash also offers the [[ .. ]] double bracket variant for conditionals, which has similarities to test:
Differences:
[[ .. ]]allows for regular expression matching with=~- Supports more string manipulation features
- Doesn‘t require quoting variables
Similarities:
- Exit code control with
$? - Supports file checks
-e,-detc - Same integer comparisons
-lt,-leetc - Logical operators
&&and||
In some cases [[ .. ]] offers advantages, but test remains more portable across shells.
Optimizing Performance
When using test heavily in Bash scripts, keep in mind that each command invokes a separate subprocess. This can impact performance if overdone.
Tips to optimize:
- Avoid repeating the same test over and over
- Combine tests with
-aand-ooperators - Consider using
[[ .. ]]where possible
Properly leveraged, test command conditionals do not usually cause issues. But always profile script performance!
Test Command Portability
The test command syntax is available on all POSIX-compliant shells including:
- Bash – The standard Linux shell since the late 80s
- Zsh – A popular alternative shell for Linux/macOS
- Ksh – The Korn shell, predecessor to Bash
- Dash – Lightweight shell used as /bin/sh
This makes scripts using test very portable. However, be aware that some of the expression syntax can vary slightly between shells.
Here is a quick compatibility table:
| Feature | Bash | Dash | Ksh | Zsh |
|---|---|---|---|---|
| Basic Expressions | Yes | Yes | Yes | Yes |
| File Checks | Yes | Yes | Yes | Yes |
| String Comparisons | Yes | Yes | Yes | Yes |
| Integer Comparisons | Yes | Yes | Yes | Yes |
| Regular Expressions | No | No | No | Yes |
| Extended Globbing | Yes | No | No | Yes |
| Arithmetic Expansion | Yes | No | Yes | Yes |
So while scripts using basic test expressions work across all shells, some advanced features will break. Always check your target platform!
In Bash, it is best to stick to common compatibility options like test and POSIX regex features only. This ensures maximum portability.
Conclusion
While simple on the surface, leveraging the test command opens up immense scripting capabilities. Striking an excellent balance between utility and simplicity, it forms the foundation for decision making in Bash scripts.
I hope this guide provided deeper insights into everything possible with this humble but powerful command! Let me know if you have any other favorite advanced test use cases or scripts.


