Does the syntax of not equal matter?

12,896

Solution 1

Beside the cosmetic/preference arguments, one reason could be that there are more implementations where [ ! "$a" = "$b" ] fails in corner cases than with [ "$a" != "$b" ].

Both cases should be safe if implementations follow the POSIX algorithm, but even today (early 2018 as of writing), there are still implementations that fail. For instance, with a='(' b=')':

$ (a='(' b=')'; busybox test "$a" != "$b"; echo "$?")
0
$ (a='(' b=')'; busybox test ! "$a" = "$b"; echo "$?")
1

With dash versions prior to 0.5.9, like the 0.5.8 found as sh on Ubuntu 16.04 for instance:

$ a='(' b=')' dash -c '[ "$a" != "$b" ]; echo "$?"'
0
$ a='(' b=')' dash -c '[ ! "$a" = "$b" ]; echo "$?"'
1

(fixed in 0.5.9, see https://www.mail-archive.com/[email protected]/msg00911.html)

Those implementations treat [ ! "(" = ")" ] as [ ! "(" "text" ")" ] that is [ ! "text" ] (test whether "text" is the null string) while POSIX mandates it to be [ ! "x" = "y" ] (test "x" and "y" for equality). Those implementations fail because they perform the wrong test in that case.

Note that there's yet another form:

! [ "$a" = "$b" ]

That one requires a POSIX shell (won't work with the old Bourne shell).

Note that several implementations have had problems with [ "$a" = "$b" ] (and [ "$a" != "$b" ]) as well and still do like the [ builtin of /bin/sh on Solaris 10 (a Bourne shell, the POSIX shell being in /usr/xpg4/bin/sh). That's why you see things like:

[ "x$a" != "x$b" ]

In scripts trying to be portable to old systems.

Solution 2

The x != y syntax is better because ! x == y is error prone - requires knowledge of operators precedence which differs from language to language. The syntax ! x == y could be interpreted as !(x == y) or (!x) == y, depending on priority of ! vs =.


For example, in c++ negation ! comes before comparison/relational operator ==, hence the following code:

#include<iostream>

using namespace std;

int main()
{
  int x=1, y=2;
  if(     x  != y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(  !  x  == y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(  !( x  == y ) ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(   (!x) == y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
}

returns

true
false
true
false

Similar behavior can be observed in many other languages, including e.g. awk - a frequently used tool in Unix world.


On the other hand, gathering operators together via x != y does not lead to any confusion as a well-established pattern. Moreover, technically speaking != is very often not two, but just one operator, so should be even marginally faster to evaluate than separate comparison and then negation. Hence, although both syntaxes work in bash I would recommend to follow x != y as it is way easier to read and maintain code which follows some standard logic.

Solution 3

This sort of thing is very opinion-based, as the "answer" depends very strongly on the way an individual's brain happens to be wired. While it is true that semantically, NOT ( A == B ) is identical to (A != B ), one might be clearer to one person and the other to another. It also is context-dependent. For example, if I have a flag set, the meanings might be more clear with one syntax over another:

if NOT ( fileHandleStatus == FS_OPEN )

as opposed to

if ( fileHandleStatus != FS_OPEN )
Share:
12,896

Related videos on Youtube

Jimmy_A
Author by

Jimmy_A

If you're automatically sure that you know what reality is and who and what is really important, if you want to operate on your default setting, then you, like me, probably won't consider possibilities that aren't annoying and miserable. But if you've really learned how to think, how to pay attention, then you'll know you have other options. It will actually be within your power to experience a crowded, hot, slow, consumer hell-type situation as not only meaningful, but sacred -- on fire with the same force that lit the stars: love, fellowship, the mystical oneness of all things deep down

Updated on September 18, 2022

Comments

  • Jimmy_A
    Jimmy_A almost 2 years

    When scripting, I usually write my ifs with the following syntax as it is easier for me to understand that what comes next is not true.

    if [ ! "$1" = "$2" ]; then
    

    Others say that the way below is better

    if [ "$1" != "$2" ]; then
    

    The thing is when I ask why and whether there are any differences no one seems to have any answer.

    So, are there any differences between the two syntaxes? Is one of them safer than the other? Or is it just a matter of preference/habit?

    • jimmij
      jimmij over 6 years
      In the first case you need to know operators priority to distinguish !(x==y) from (!x)==y.
    • Jimmy_A
      Jimmy_A over 6 years
      @jimmij Do you mean that when comparing a string this if [ ! "$string" = "one" ] translates to if not the value of $string equals one. And this if [ "$string" != "one"] translates to if the value of $string does not equal with one?
    • jimmij
      jimmij over 6 years
      @Jimmy_A I mean that you need to know how this "translates". Gathering operators together (!= syntax) is just more obvious.
    • Kevin
      Kevin over 6 years
      Dear close voters, Stéphane's answer shows that there is a material difference in behavior, the correct answer is not in any way opinion-based.
  • derobert
    derobert over 6 years
    And even if ( FS_OPEN != fileHandleStatus ) as a result of the ease of accidentally typing = instead of == in languages where the former is assignment and the later equality test (like C)...
  • Jimmy_A
    Jimmy_A over 6 years
    So in other words, both syntax do the same, no differences whatsoever, but with ! "$a" = "b" you need to be more careful on how you write it to specify the comparison. From your example I understand that the second command returns not zero which could be both beneficial or troubling. It could be beneficial if you want to exit if they do not match, or troubling if you want to see whether the comparison crashed
  • Stéphane Chazelas
    Stéphane Chazelas over 6 years
    @Jimmy_A, no, in those implementations [ ! "$a" = "$b" ] just fail when $a is ( and $b is ), it claims they are identical when they're not, ( is not the same string as ), but [ performs the wrong test in that case.
  • Jimmy_A
    Jimmy_A over 6 years
    Ahhh, I think I got it. The first and third mean to check if the condition is true, while the second and fourth if the condition is false. Thus, the exit status codes being different. Its basically saying, 1 & 4 variables are different and 2 & 3 not equal.
  • Wildcard
    Wildcard over 6 years
    @Jimmy_A, no. You've completely missed the point. If these implementations followed POSIX, then all status codes would be 0.
  • Jimmy_A
    Jimmy_A over 6 years
    @Wildcard missed the sentence mentioning that.
  • Jimmy_A
    Jimmy_A over 6 years
    @StéphaneChazelas That is a really great explanation. Thank you