Was ist der Unterschied zwischen einfachen und doppelten Gleichheitszeichen (=) bei Shell-Vergleichen?

28

Lesen Sie, dass zum Vergleichen der Zeichenfolgen ifdoppelte eckige Klammern verwendet werden müssen. In einigen Büchern heißt es, dass der Vergleich durch erfolgen kann =. Aber es funktioniert auch mit ==.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

Gibt es einen Unterschied zwischen =und ==im Vergleich?

user3539
quelle
4
Gibt es hier irgendwo eine Frage? Wenn ja, sehe ich es nicht. =ist für [. ==ist für [[.
Chris Down
@ ChrisDown Das ist absolut nicht wahr.
Xdavidliu
@xdavidliu Pflege zu erarbeiten? Laut POSIX, das keine Ahnung hat, ist dies sicherlich der Fall ==, weshalb Sie =(Gleichheit) mit [und ==(Mustervergleich, mit Semantik, die zitierfähig ist) mit verwenden sollten [[. Siehe help testvs help [[.
Chris Down
@ ChrisDown vielleicht missverstehe ich, was mit "ist für" gemeint ist. Wenn "ist für" bedeutet "funktioniert nur mit", dann ist der Kommentar nicht wahr, da er mit [ foo == foo ] && echo fooSicherheit gedruckt wird foound anzeigt, dass er mit ==funktioniert [. Wenn jedoch mit "ist für" gemeint ist, dass "mit" verwendet werden sollte, dann habe ich weniger Einwände.
xdavidliu

Antworten:

28

[[ $a == $b ]]ist kein Vergleich, es ist Mustervergleich. Sie benötigen [[ $a == "$b" ]]für den Vergleich der Byte-zu-Byte-Gleichheit. =ist dasselbe wie ==in jeder anderen Shell, die unterstützt [[...]](eingeführt von ksh).

[[...]]ist keine Standardsyntax sh. Der [ Befehl ist Standard, und der Standard - Vergleich Operator ist =(obwohl einige [Implementierungen auch erkennen ==).

Wie in jedem Argument eines Befehls müssen Variablen in Anführungszeichen gesetzt werden.

[ "$a" = "$b" ]

Standardmäßig sherfolgt der Musterabgleich mit case:

case $a in
  ($b) ...
esac

Der Vollständigkeit halber andere gleichheitsähnliche Operatoren, auf die Sie in Shell-Skripten stoßen können:

  • [ "$a" -eq "$b" ]: Standardoperator [zum Vergleichen von Dezimalzahlen. Einige [Implementierungen erlauben Leerzeichen um die Zahlen, andere erlauben beliebige arithmetische Ausdrücke, aber das ist nicht portierbar. Portabel kann man [ "$((a))" -eq "$((b))" ]dafür verwenden. Siehe auch [ "$((a == b))" -ne 0 ]die die Standard - äquivalent wäre (außer , dass POSIXly wird das Verhalten nur dann angegeben , wenn $aund $benthält ganzzahlige Konstanten) von:
  • ((a == b)), from ksh und auch gefunden in zshund bash, gibt true zurück, wenn die Auswertung des in gespeicherten arithmetischen Ausdrucks $adieselbe Zahl ergibt wie die von $b. In der Regel wird dies zum Vergleichen von Zahlen verwendet. Beachten Sie, dass es zwischen den Shells Unterschiede gibt, wie arithmetische Ausdrücke ausgewertet werden und welche Zahlen unterstützt werden (z. B. unterstützen bash und einige Implementierungen / Versionen von ksh keine Gleitkommazahlen oder behandeln Zahlen mit führenden Nullen als Oktal).

  • expr "$a" = "$b"führt einen Zahlenvergleich durch, wenn beide Operanden als dezimale Ganzzahlen erkannt werden (einige erlauben Leerzeichen um die Zahl), und überprüft andernfalls, ob die beiden Zeichenfolgenoperatoren dieselbe Sortierreihenfolge haben. Es wäre auch für Werte von fehlschlagen $aoder $b, die exprOperatoren wie (, substr...

  • awk 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": Wenn $aund $bals Zahlen erkannt werden (mindestens dezimale Ganzzahl- und Gleitkommazahlen wie 1,2, -1,5e-4, führende nachgestellte Leerzeichen werden ignoriert, einige erkennen auch hexadezimal, oktal oder irgendetwas, was von erkannt wird strtod()), wird ein numerischer Vergleich durchgeführt. Ansonsten je nach Implementierung, dann ist es entweder ein Byte-zu-Byte - String - Vergleich oder dergleichen für expreinen strcoll()Vergleich, dh ob $aund $bArt gleich.

Siehe auch:

Stéphane Chazelas
quelle
13

Dies sind äquivalente in Bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

Die ersten beiden Variablen $ x müssen nicht in Anführungszeichen gesetzt werden. Bash führt die Worttrennung und Pfadnamenerweiterung innerhalb von [aber nicht innerhalb von [[durch:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]]ist ein Zeichenkettenvergleich, aber [[ $x = $y ]]ein Mustervergleichsausdruck:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq soll nur mit ganzen Zahlen verwendet werden:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

Siehe auch BashFAQ / 031: Was ist der Unterschied zwischen test, [und [[? .

Lri
quelle