Kommt es auf die Syntax von Ungleichem an?

22

Beim Schreiben von Skripten schreibe ich meine ifs normalerweise mit der folgenden Syntax, da ich leichter verstehen kann, dass das, was als Nächstes kommt, nicht wahr ist.

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

Andere sagen, dass der Weg unten besser ist

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

Die Sache ist, wenn ich frage, warum und ob es irgendwelche Unterschiede gibt, scheint niemand eine Antwort zu haben.

Gibt es also Unterschiede zwischen den beiden Syntaxen? Ist einer sicherer als der andere? Oder ist es nur eine Frage der Präferenz / Gewohnheit?

Jimmy_A
quelle
9
Im ersten Fall müssen Sie die Priorität der Operatoren kennen, um !(x==y)von diesen unterscheiden zu können (!x)==y.
Jimmy
@jimmij Meinen Sie , dass , wenn eine Zeichenfolge zu vergleichen diese if [ ! "$string" = "one" ]zu übersetzen , wenn nicht der Wert von $stringGleichen one. Und das heißt if [ "$string" != "one"], wenn der Wert von $stringnicht gleich ist one?
Jimmy_A
5
@ Jimmy_A Ich meine, dass Sie wissen müssen, wie dies "übersetzt". Das Zusammenführen von Operatoren ( !=Syntax) ist nur offensichtlicher.
Jimmy
Sehr geehrte Wählerinnen und Wähler, die Antwort von Stéphane zeigt, dass es einen wesentlichen Unterschied im Verhalten gibt, die richtige Antwort ist in keiner Weise meinungsbasiert.
Kevin

Antworten:

35

Neben den kosmetischen / Präferenz-Argumenten könnte ein Grund sein, dass es mehr Implementierungen gibt, bei denen [ ! "$a" = "$b" ]in Eckfällen Fehler auftreten als bei [ "$a" != "$b" ].

Beide Fälle sollten sicher sein, wenn Implementierungen dem POSIX-Algorithmus folgen , aber selbst heute (Anfang 2018, wie zum Zeitpunkt des Schreibens) gibt es noch Implementierungen, die fehlschlagen. Zum Beispiel mit a='(' b=')':

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

Mit dashVersionen vor 0.5.9, wie zum Beispiel der Version 0.5.8 shauf Ubuntu 16.04:

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

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

Diese Implementierungen behandeln [ ! "(" = ")" ]wie [ ! "(" "text" ")" ]das ist [ ! "text" ](Test , ob „text“ ist der Null - String) , während POSIX Mandate es zu sein [ ! "x" = "y" ](Test „x“ und „y“ für die Gleichstellung). Diese Implementierungen schlagen fehl, weil sie in diesem Fall den falschen Test durchführen.

Beachten Sie, dass es noch ein anderes Formular gibt:

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

Dieser benötigt eine POSIX-Shell (funktioniert nicht mit der alten Bourne-Shell).

Beachten Sie, dass einige Implementierungen ebenfalls Probleme mit [ "$a" = "$b" ](und [ "$a" != "$b" ]) hatten und immer noch mit dem in Solaris 10 integrierten [Betriebssystem /bin/sh(einer Bourne-Shell, in der sich die POSIX-Shell befindet /usr/xpg4/bin/sh) übereinstimmen . Deshalb sehen Sie Dinge wie:

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

In Skripten, die versuchen, auf alte Systeme portierbar zu sein.

Stéphane Chazelas
quelle
Mit anderen Worten, beide Syntaxen haben die gleiche Wirkung, es gibt keinerlei Unterschiede, aber ! "$a" = "b"Sie müssen vorsichtiger sein, wie Sie sie schreiben, um den Vergleich festzulegen. Aus Ihrem Beispiel geht hervor, dass der zweite Befehl not zeronützlich oder beunruhigend sein kann. Es kann nützlich sein, wenn Sie
beenden
2
@Jimmy_A, nein, in diesen Implementierungen [ ! "$a" = "$b" ]scheitern nur wenn $aist (und $bist ), sie behauptet , dass sie identisch sind , wenn sie es nicht sind , (ist nicht die gleiche Zeichenfolge wie ), aber [führt die falsche Test in diesem Fall.
Stéphane Chazelas
Ahhh, ich glaube ich habe es verstanden. Das erste und dritte Mittel, um zu prüfen, ob die Bedingung wahr ist, während das zweite und vierte, ob die Bedingung falsch ist. Daher sind die Ausgangsstatuscodes unterschiedlich. Grundsätzlich heißt es, 1 & 4 Variablen sind unterschiedlich und 2 & 3 nicht gleich.
Jimmy_A
3
@ Jimmy_A, nein. Sie haben den Punkt völlig verpasst. Wenn diese Implementierungen POSIX folgen würden, wären alle Statuscodes 0.
Wildcard
Um sicherzugehen, dass ich das verstehe, [ ! "$a" = "$b" ]läuft dies auf Folgendes hinaus: Wird in Buggy-Shell-Implementierungen manchmal falsch gehandhabt (was meiner Meinung nach mehr oder weniger den ersten Satz der Antwort wiedergibt).
Michael Burr
8

Die x != ySyntax ist besser, weil sie ! x == yfehleranfällig ist - erfordert Kenntnisse über die Rangfolge der Operatoren, die von Sprache zu Sprache unterschiedlich sind. Die Syntax kann je nach Priorität von vs ! x == yals !(x == y)oder interpretiert werden .(!x) == y!=


Zum Beispiel kommt in der c++Negation ! der Vergleichsoperator / Vergleichsoperator vor == , daher der folgende 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;
}

kehrt zurück

true
false
true
false

Ein ähnliches Verhalten kann in vielen anderen Sprachen beobachtet werden, einschließlich z. B. awk- einem in der Unix-Welt häufig verwendeten Tool.


Auf der anderen Seite führt das Sammeln von Operatoren über x != ykeine Verwirrung als ein gut etabliertes Muster. Im Übrigen sind es technisch gesehen !=oft nicht zwei, sondern nur ein Operator, weshalb die Auswertung geringfügig schneller sein sollte als der separate Vergleich und die anschließende Verneinung. Daher würde ich empfehlen, obwohl beide Syntaxen in bash funktionieren, zu folgen, x != yda es viel einfacher ist, Code zu lesen und zu warten, der einer Standardlogik folgt.

jimmij
quelle
4

Diese Art von Dingen ist sehr meinungsbasiert, da die "Antwort" sehr stark davon abhängt, wie das Gehirn eines Individuums verdrahtet ist. Zwar stimmt das semantisch, NOT ( A == B )ist aber identisch mit(A != B ) , könnte einer für eine Person klarer sein und der andere für eine andere. Es ist auch kontextabhängig. Wenn ich zum Beispiel ein Flag gesetzt habe, sind die Bedeutungen bei einer Syntax klarer als bei einer anderen:

if NOT ( fileHandleStatus == FS_OPEN )

im Gegensatz zu

if ( fileHandleStatus != FS_OPEN )
DopeGhoti
quelle
Und selbst if ( FS_OPEN != fileHandleStatus )als Ergebnis der Leichtigkeit des versehentlichen Tippens =statt ==in Sprachen, in denen das erstere Aufgabe ist und der spätere Gleichheitstest (wie C) ...
derobert