Does the syntax of not equal matter?

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.


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.


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 )

Tags:

Shell

Test