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/dash@vger.kernel.org/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.
!(x==y)
from(!x)==y
. – jimmij Jan 12 '18 at 16:23if [ ! "$string" = "one" ]
translates to if not the value of$string
equalsone
. And thisif [ "$string" != "one"]
translates to if the value of$string
does not equal withone
? – Jimmy_A Jan 12 '18 at 16:33!=
syntax) is just more obvious. – jimmij Jan 12 '18 at 16:48