349

This script is getting an error:

elif [ $operation = "man" ]; then
    if [ $aug1 = "add" ]; then         # <- Line 75
    echo "Man Page for: add"
    echo ""
    echo "Syntax: add [number 1] [number 2]"
    echo ""
    echo "Description:"
    echo "Add two different numbers together."
    echo ""
    echo "Info:"
    echo "Added in v1.0"
    echo ""
elif [ -z $aug1 ]; then
    echo "Please specify a command to read the man page."
else
    echo "There is no manual page for that command."
fi

I get this error:

calc_1.2: line 75: [: =: unary operator expected
alex
  • 6,818
  • 9
  • 52
  • 103
Jordanss10
  • 3,821
  • 3
  • 15
  • 16

6 Answers6

754

If you know you're always going to use Bash, it's much easier to always use the double bracket conditional compound command [[ ... ]], instead of the POSIX-compatible single bracket version [ ... ]. Inside a [[ ... ]] compound, word-splitting and pathname expansion are not applied to words, so you can rely on

if [[ $aug1 == "and" ]];

to compare the value of $aug1 with the string and.

If you use [ ... ], you always need to remember to double quote variables like this:

if [ "$aug1" = "and" ];

If you don't quote the variable expansion and the variable is undefined or empty, it vanishes from the scene of the crime, leaving only

if [ = "and" ];

which is not a valid syntax. (It would also fail with a different error message if $aug1 included white space or shell metacharacters.)

The modern [[ operator has lots of other nice features, including regular expression matching.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rici
  • 234,347
  • 28
  • 237
  • 341
  • 12
    "modern"? Hasn't [[ *always* been in bash? It has been in Korn shell for over twenty years, and pre-dates bash. (I know what you mean though) – cdarke Nov 29 '12 at 09:04
  • @cdarke Fwiw, per page 113 in the 3rd Edition of Learning the Bash Shell, "[[ .. ]] is not available in versions of bash prior to 2.05." In the online pdf from doc.lagout.org, it's on page 326! – spen.smith Jul 31 '20 at 07:18
  • 2
    @spen.smith: according to the [Bash FAQ](https://mywiki.wooledge.org/BashFAQ/061), `[[` was added to Bash in v2.02 (1998), based on the `ksh` feature available since the 1980s. In 2012, when cdarke wrote that comment, it was already reasonable to say that it was "in Korn shell for over 20 years." My use of the word "modern" in 2012 was certainly questionable; today, it would be ridiculous. But then, there are still programmers who insist that a C standard published 21 years ago is too modern to use :-) – rici Jul 31 '20 at 19:11
  • 2
    Ah that's super interesting. Haha! Thanks for the correction. – spen.smith Jul 31 '20 at 19:15
  • 2
    @timo: yes, it will work. Many people prefer to quote `"$aug1"` although it is not necessary. – rici Jun 15 '21 at 16:08
50

It took me a while to find this, but note that if you have a spacing error, you will also get the same error:

[: =: unary operator expected

Correct:

if [ "$APP_ENV" = "staging" ]

vs

if ["$APP_ENV" = "staging" ]

As always, setting -x debug variable helps to find these:

set -x
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Juha Vehnia
  • 1,255
  • 12
  • 15
8

Try assigning a value to $aug1 before use it in if[] statements; the error message will disappear afterwards.

sitilge
  • 3,687
  • 4
  • 30
  • 56
yilee
  • 87
  • 2
  • 3
1

Make sure that when comparing a variable like $operation using string comparison you do not leave the possibility that $operation returns an empty string if you use the POSIX approach (single bracket).

Both [ $operation == "man"] and [ "" == "man" ] return the same error: [: ==: unary operator expected

Also, you shouldn't use the = operator unless you double bracket, as stated above.

Reference: https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html

eco
  • 1,254
  • 1
  • 12
  • 22
0

This error can also occur reading numerical input that could possibly be blank (to accept a default option).

The solution is to structure the if statement with multiple conditions & test for an empty variable first.

For example:

# sanitise input
var=$(echo $ans | tr -cd "[:digit:]")

if [ -z "$var" ] || [ "$var" -lt 1 ]; then
   do_something
fi

I had to solve this unary operator expected issue in remove_old_pkgs() of the helper script abk for Arch Sign Modules.

See also 6.4 Bash Conditional Expressions

Stuart Cardall
  • 2,099
  • 24
  • 18
  • Related: *[What does -z mean in Bash?](https://stackoverflow.com/questions/18096670)* – Peter Mortensen Oct 05 '21 at 14:24
  • Related: *[Boolean operators ( &&, -a, ||, -o ) in Bash](https://stackoverflow.com/questions/20449680/)* – Peter Mortensen Oct 05 '21 at 15:38
  • It ***appears*** as if the logic is inverted (compared to how it should be). Can you elaborate in detail what is going in your answer (e.g., so it is very clear why it is `-z` and not `-n`)? And why not `&&` instead of `||`? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/69178804/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Oct 05 '21 at 15:38
  • Following the logic of that statement, it should just be [ "$var" -le "0" ] && { do_something; }; -z is a check if the variable == "" and -n is != "" – That one guy from the movie Oct 08 '21 at 19:53
-14

You can also set a default value for the variable, so you don't need to use two "[", which amounts to two processes ("[" is actually a program) instead of one.

It goes by this syntax: ${VARIABLE:-default}.

The whole thing has to be thought in such a way that this "default" value is something distinct from a "valid" value/content.

If that's not possible for some reason you probably need to add a step like checking if there's a value at all, along the lines of "if [ -z $VARIABLE ] ; then echo "the variable needs to be filled"", or "if [ ! -z $VARIABLE ] ; then #everything is fine, proceed with the rest of the script".

  • 4
    `[[` is not spawning two processes, it is a shell builtin (and `[` is a Bash builtin too). `[[` is different from `[ [`, which treats the second `[` as a string – user123444555621 May 01 '14 at 08:18