Why equal to operator does not work if it is surrounded by space?

14,001

Solution 1

test (or [ expr ]) is a builtin function. Like all functions in bash, you pass it's arguments as whitespace separated words.

As the man page for bash builtins states: "Each operator and operand must be a separate argument."

It's just the way bash and most other Unix shells work.

Variable assignment is different.

In bash a variable assignment has the syntax: name=[value]. You cannot put unquoted spaces around the = because bash would not interpret this as the assignment you intend. bash treats most lists of words as a command with parameters.

E.g.

# call the command or function 'abc' with '=def' as argument
abc =def

# call 'def' with the variable 'abc' set to the empty string
abc= def

# call 'ghi' with 'abc' set to 'def'
abc=def ghi

# set 'abc' to 'def ghi'
abc="def ghi"

Solution 2

When the shell reads

if [ "$var1" = "$var2" ]

it invokes the command [ with 4 arguments. Whether [ is a builtin or an external command is irrelevant, but it may help to understand that it may be the external command /bin/[. The second argument is the literal '=' and the fourth is ']'. However, when the shell reads

if [ "$var1"= "$var2" ]

[ only gets 3 arguments: the expansion of $var1 with '=' appended, the expansion of $var2, and ']'. When it gets only 3 arguments, it expects the last argument to be ']' and the first argument to be a unary operator.

Solution 3

To add to the existing explanation, "$var1"="$var2" is just a single non-empty string, and thus always evaluates as true in a conditional.

[ "$var1"="$var2" ] && echo true

The above command will always print out true (even if var1 and var2 be empty).

Share:
14,001

Related videos on Youtube

Andrew-Dufresne
Author by

Andrew-Dufresne

Call me Talha. I go by “talha131” at Github, DEV, and GoodReads. Email is the best way to reach me. I work on Jump Desktop. It is a remote desktop application for iOS, Android, macOS, and Windows. I play a broad role there; which includes research, product design, engineering, and deployment. I also lend a hand in user support. I have been working in the field for more than a decade. I do not pigeonhole myself to specific languages or frameworks. Through the years, I have learned and worked in several programming languages and frameworks. I have built apps for macOS, Windows, Linux, iOS, and Android. I am comfortable working in C, C++, Objective-C, C#, Python, and Java. I took up web development since early 2016 and picked up Go and NodeJS. I have built and delivered apps using ReactJS, Mobx, Redux, and ElectronJS. Besides the day job, I contribute to open source projects, beta test startup products, and offer consultancy. I work on my physical fitness and read books regularly; to be a stronger and better version of myself!

Updated on March 24, 2022

Comments

  • Andrew-Dufresne
    Andrew-Dufresne about 2 years

    I tried the following script

    #!/bin/bash
    var1="Test 1" 
    var2="Test 2"
    if [ "$var1"="$var2" ] 
      then 
        echo "Equal" 
      else 
        echo "Not equal"
    fi
    

    It gave me Equal. Although it should have printed Not equal

    Only when I inserted space around = it worked as intended

    if [ "$var1" = "$var2" ] 
    

    and printed Not equal

    Why is it so? Why "$var1"="$var2" is not same as "$var1" = "$var2"?

    Moreover, when I wrote if [ "$var1"= "$var2" ], it gave

    line 4: [: Test 1=: unary operator expected
    

    What does it it mean? How come its expecting unary operator?

  • Andrew-Dufresne
    Andrew-Dufresne about 13 years
    Thanks Charles Bailey. There is one thing more, as man page says "each operator and ...." then why var = "test" ; does not work? To make it work, I have to remove spaces var="test"; Is assignment = is not an operator?
  • CB Bailey
    CB Bailey about 13 years
    That man page applies to the test builtin function. In bash a variable assignment is part of the shell grammar, it's not a function. It requires no spaces.
  • William Pursell
    William Pursell about 13 years
    ...and 'abc = def' invokes the command abc with two arguments '=' and 'def'
  • tripleee
    tripleee over 8 years
    Bash[[ is governed by the same shell syntax as all other constructs. Switching to [[ would not solve the OP's problem. As to whether this is "better" depends on whether you prioritize convenience over portability. If you are committed to Bash-only, it's probably true.
  • knesenko
    knesenko over 8 years
    As I wrote, I meant bash. Of course if you want your code to be portable, you should use /bin/sh
  • tripleee
    tripleee over 8 years
    Still, this does not attempt to address the OP's question, and should be posted as a comment instead (if at all).
  • linuxfan says Reinstate Monica
    linuxfan says Reinstate Monica about 2 years
    @knesenko you should read better both questions and comments...