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, -d etc
  • Same integer comparisons -lt, -le etc
  • 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 -a and -o operators
  • 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.

Similar Posts