What does “unary operator expected” mean in Bash?

The first time I saw the error “Bash Unary Operator Expected” in the Linux terminal I thought:”And now? What do I do?” 😀

We will understand this error together and we will find a solution for it.

What is the Bash Unary Operator Expected error?

It’s an error that occurs when Bash identifies a line in your script that contains a binary operator that is not applied to two arguments. When this happens Bash assumes that you want to use a unary operator instead and raises the Unary Operator Expected error.

It might not be 100% clear if it’s the first time you hear about unary and binary operators.

That’s ok we will look at this together and by the end of this article you will know how to fix this error in your scripts.

Let’s figure it out!

What Causes The Bash Unary Operator Expected Error

The best way to understand an error is to write code where the error occurs and then go through any changes required to fix the error.

So, let’s follow this principle!

I will start with a simple Bash script called unary.sh:

#!/bin/bash

DAY="monday"

if [ $DAY == "monday" ]; then
    echo "Today is monday"
fi

When I run the script I get the following output:

[myuser@localhost]$ ./unary.sh
Today is monday

Now, let’s update line 3 of our script from:

DAY="monday"

to:

DAY=

After this change the variable DAY is empty.

Let’s run the script again…

[myuser@localhost]$ ./unary.sh
./unary.sh: line 5: [: ==: unary operator expected

This time we see the error “unary operator expected”. Why?

Sometimes Bash errors don’t make much sense, or at least it looks like they don’t.

Why Bash is expecting a unary operator? And what is a unary operator?

Bash Unary and Binary Operators

What are unary and binary operators?

Bash operators are used in expressions that verify conditions as part of the logic of a script. Unary operators apply to one argument and are often used to verify the status of a file (e.g. does a specific file exist?). Binary operators apply to two arguments and are used, for example, as part of string or arithmetic comparisons (e.g. is a bigger than b?).

Now the error we are seeing makes a bit more sense.

./unary.sh: line 5: [: ==: unary operator expected

At line 5 of our script Bash is expecting a unary operator but the one we are using ( == ) is a binary operator.

It still doesn’t make complete sense but we are getting there…

Here is what happens when Bash reaches line 5 of the script:

if [ $DAY == "monday" ]; then

It replaces $DAY with its value, that in the first example is “monday”, so the line becomes:

if [ "monday" == "monday" ]; then

This expression is true and the echo command inside the if statement gets executed.

The operator == is a binary operator because it compares two values (arguments), the one on the left side of the operator with the one on the right side.

But, what happens when the value of the variable DAY is empty?

Line 5 of our script becomes:

if [ == "monday" ]; then

As you can see the left side of the comparison expression disappears and that’s why Bash prints the error “unary operator expected”.

Because the expression doesn’t contain two values anymore, but only one, “monday”.

How to Fix the Bash Unary Operator Expected Error

Now that we have a better understanding of the error, we also want to understand how to fix it.

How can we make sure our original expressions keeps both arguments even when the variable DAY is empty?

The solution is surrounding the variable $DAY in the comparison expression with double quotes.

The script becomes:

#!/bin/bash

DAY=

if [ "$DAY" == "monday" ]; then
    echo "Today is monday"
fi

Notice how $DAY has become “$DAY”…

This time, when the variable DAY is empty and Bash reaches line 5 of the code, the if statement becomes:

if [ "" == "monday" ]; then

In this way the comparison expression is still valid. In this case the value of the expression is false and the script doesn’t print any output (and doesn’t error in the way we have seen before):

[myuser@localhost]$ ./unary.sh
[myuser@localhost]$

Does it make sense?

Bash Unary Operator Expected with While Loop

Let’s look at another script in which the same error occurs.

This time we will use a while loop in our script…

#!/bin/bash

while [ $INDEX -lt 5 ]
do
    echo $INDEX
    INDEX=$((INDEX+1))
done

I have created a simple script that uses a while loop to print the value of the variable INDEX and increase its value until it reaches 5.

When I run the script the error shows up again:

[myuser@localhost]$ ./unary_while.sh
./unary_while.sh: line 3: [: -lt: unary operator expected

Why?

One way to troubleshoot errors in a Bash script is by running the script using the following command:

bash -x <script_name>

Let’s give it a try:

[myuser@localhost]$ bash -x unary_while.sh
+ '[' -lt 5 ']'
unary_while.sh: line 3: [: -lt: unary operator expected

As you can see this allows to see the way each line is interpreted by the Bash interpreter.

The problem is in the following line:

+ '[' -lt 5 ']'

The -lt comparison operator is a binary operator used to compare two numbers, but in this case we can see only the number on the right side of the operator (the number 5).

What happened to the number of its left side?

It’s missing because we haven’t defined the variable INDEX before the while loop…

…let’s do it now:

#!/bin/bash

INDEX=0

while [ $INDEX -lt 5 ]
do
    echo $INDEX
    INDEX=$((INDEX+1))
done

This time when we run the script we get the expected result:

[myuser@localhost]$ ./unary_while.sh
0
1
2
3
4

And here is the way the bash -x output looks like this time:

[myuser@localhost]$ bash -x unary_while.sh
+ INDEX=0
+ '[' 0 -lt 5 ']'
+ echo 0
0
+ INDEX=1
+ '[' 1 -lt 5 ']'
+ echo 1
1
+ INDEX=2
+ '[' 2 -lt 5 ']'
+ echo 2
2
+ INDEX=3
+ '[' 3 -lt 5 ']'
+ echo 3
3
+ INDEX=4
+ '[' 4 -lt 5 ']'
+ echo 4
4
+ INDEX=5
+ '[' 5 -lt 5 ']'

Can you see how the value of the INDEX variable inside the test expression of the while loop increases at every iteration?

The script stops when INDEX reaches the value 5 because at that point the test expression of the while loop becomes false.

Unary Operator Expected when Checking For Empty String

One way to check if a string is empty in Bash is using the following if statement:

#!/bin/bash

MYSTRING=

if [ $MYSTRING == '' ]; then
    echo "The string MYSTRING is empty"
fi

For the reasons explained in the previous sections the if statement will cause the “unary operator expected” error considering that the variable MYSTRING is empty.

Does it make sense?

As we have learned, one workaround would be surrounding $MYSTRING in the if statement with double quotes:

#!/bin/bash

MYSTRING=

if [ "$MYSTRING" == '' ]; then
    echo "The string MYSTRING is empty"
fi

The script works well this time:

[myuser@localhost]$ ./unary_string.sh
The string MYSTRING is empty

To achieve the same purpose we can replace the binary operator == with the unary operator -z, that is used to verify if a string is empty.

If we use the -z test operator, the script becomes cleaner:

#!/bin/bash

MYSTRING=

if [ -z $MYSTRING ]; then
    echo "The string MYSTRING is empty"
fi

You can run it and make sure you receive the output “The string MYSTRING is empty”.

Test Expression with Double Square Brackets

Another way to solve the error we are learning about in this article, is by using test expressions with double square brackets ( [[ … ]] ) instead of single square brackets ( [ … ] ).

Let’s see how it works for the script that wasn’t working before (I have replaced [] with [[ ]]):

#!/bin/bash

MYSTRING=

if [[ $MYSTRING == '' ]]; then
    echo "The string MYSTRING is empty"
fi

The script works fine:

[myuser@localhost]$ ./unary_string.sh
The string MYSTRING is empty

Why?

We can see why using the bash -x command:

[myuser@localhost]$ bash -x unary_string.sh 
+ MYSTRING=
+ [[ '' == '' ]]
+ echo 'The string MYSTRING is empty'
The string MYSTRING is empty

As you can see, this time even if the variable MYSTRING is empty the comparison in the if statement contains empty strings for both arguments:

+ [[ '' == '' ]]

And for this reason we don’t see the unary operator expected error.

In a future article I will explain the difference between single and double brackets in Bash with some examples.

Conclusion

Quite an interesting error this one!

Now you know what to do if you see the “unary operator expected” error and you also know which parts of your scripts are likely to cause it.

In summary, the first place to look for is a Bash binary operator that compares the value of a variable with either a string or a number.

Once you find it have a look at what could make that variable empty and also if you are surrounding that variable with double quotes.

And you? Where are you seeing this error in your scripts?

Let me know in the comments below 🙂


Related FREE Course: Decipher Bash Scripting

Leave a Comment