Was ist der Unterschied zwischen [[$ a == z *]] und [$ a == z *]?

35

Gibt es einen Unterschied zwischen diesen beiden.

[[ $a == z* ]]

und

[ $a == z* ] 

Kann ich ein Beispiel haben, in dem sie unterschiedliche Ausgaben haben würden?

Inwiefern unterscheidet sich die Arbeitsweise [[ ]]von [ ]?

münchen
quelle

Antworten:

41

Der Unterschied zwischen [[ … ]]und [ … ]wird meistens durch die Verwendung von Single- oder Double-Bracket-Bash abgedeckt . Entscheidend [[ … ]]ist eine spezielle Syntax, wohingegen [es sich bei einem Befehl um einen komisch aussehenden Namen handelt. [[ … ]]hat spezielle Syntaxregeln für das, was drin ist, [ … ]nicht.

Mit der zusätzlichen Falte eines Platzhalters wird Folgendes [[ $a == z* ]]bewertet:

  1. Analysieren Sie den Befehl: Dies ist das [[ … ]]bedingte Konstrukt um den bedingten Ausdruck $a == z*.
  2. Analysieren Sie den Bedingungsausdruck: Dies ist der ==Binäroperator mit den Operanden $aund z*.
  3. Erweitern Sie den ersten Operanden in den Wert der Variablen a.
  4. Bewerten Sie den ==Operator: Testen Sie, ob der Wert der Variablen amit dem Muster übereinstimmt z*.
  5. Bewerten Sie den Bedingungsausdruck: Das Ergebnis ist das Ergebnis des Bedingungsoperators.
  6. Der Befehl wird jetzt ausgewertet, sein Status ist 0, wenn der bedingte Ausdruck wahr war, und 1, wenn er falsch war.

So [ $a == z* ]wird bewertet:

  1. Parse den Befehl: Dies ist der [Befehl mit den Argumenten , die durch die Worte Auswertung $a, ==, z*, ].
  2. Erweitern Sie $aden Wert der Variablen a.
  3. Führen Sie die Wortteilung und Dateinamengenerierung für die Parameter des Befehls durch.
    • Wenn beispielsweise der Wert aist der 6-stellige Zeichenfolge foo b*(erhalten durch zB a='foo b*') und die Liste der Dateien im aktuellen Verzeichnis ( bar, baz, qux, zim, zum), dann ist das Ergebnis der Expansion ist die folgende Liste von Worten: [, foo, bar, baz, ==, zim, zum, ].
  4. Führen Sie den Befehl [mit den im vorherigen Schritt erhaltenen Parametern aus.
    • Mit den obigen Beispielwerten [meldet der Befehl einen Syntaxfehler und gibt den Status 2 zurück.

Hinweis: In [[ $a == z* ]]Schritt 3 wird der Wert von akeiner Wortteilung und Dateinamengenerierung unterzogen, da in diesem Kontext ein einzelnes Wort erwartet wird (das linke Argument des bedingten Operators ==). Wenn ein einzelnes Wort an dieser Position Sinn macht, verhält sich die Variablenerweiterung in den meisten Fällen wie in doppelten Anführungszeichen. Es gibt jedoch eine Ausnahme von dieser Regel: [[ abc == $a ]]Wenn der Wert von aPlatzhalter enthält, awird er mit dem Platzhaltermuster abgeglichen. Wenn beispielsweise der Wert von aist, a*dann [[ abc == $a ]]ist er wahr (weil der Platzhalter *aus der nicht zitierten Erweiterung von $aÜbereinstimmungen stammt *), während er [[ abc == "$a" ]]falsch ist (weil das gewöhnliche Zeichen ist)*aus der angegebenen Erweiterung von $anicht übereinstimmen bc). Innen [[ … ]], doppelte Anführungszeichen keinen Unterschied machen, außer auf der rechten Seite der String - Matching Operatoren ( =, ==, !=und =~).

Gilles 'SO - hör auf böse zu sein'
quelle
39

[ist ein Alias ​​für den testBefehl. Unix Version 6 hatte eineif Befehl, aber Version 7 (1979) enthielt die neue Bourne-Shell , die einige Programmierkonstrukte einschließlich des if-then-else-elif-fi-Konstrukts enthielt, und Unix Version 7 fügte einen testBefehl hinzu , der die meisten der Befehle ausführte "tests", die vom ifKommando in älteren Versionen durchgeführt wurden.

[ wurde zu einem Pseudonym gemacht test und beide wurden in die Shell in Unix System III (1981) eingebaut . Es sollte jedoch beachtet werden, dass einige Unix-Varianten [erst viel später einen Befehl hatten ( bis in die frühen 2000er Jahre auf einigen BSDs, shdie auf der Almquist-Shell basieren (ein testBuiltin war immer in ashder Quelle enthalten, aber auf diesen) BSDs war es zunächst deaktiviert)).

Beachten Sie, dass test aka [ein Befehl zum Ausführen von "Tests" ist. Es gibt keine Zuweisung, die dieser Befehl ausführt. Es gibt also keinen Grund, zwischen einer Zuweisung und einem Gleichheitsoperator zu unterscheiden =. ==wird nur von einigen aktuellen Implementierungen von unterstützt [(und ist nur ein Alias ​​für =).

Da [es sich nur um einen Befehl handelt, wird er wie jeder andere Befehl von der Shell analysiert.

Insbesondere würde in Ihrem Beispiel, $ada es nicht in Anführungszeichen gesetzt ist, nach den üblichen Regeln der Wortteilung in mehrere Wörter aufgeteilt, und jedes Wort würde einer Dateinamengenerierung, auch Globbing genannt, unterzogen, um möglicherweise mehr Wörter zu erhalten, wobei jedes dieser Wörter Folgendes ergibt ein separates Argument zum [Befehl.

Ebenso z*würde die Liste der Dateinamen im aktuellen Verzeichnis beginnend mit erweitert z.

So zum Beispiel, wenn $aist b* = x, und es gibt z1, z2, b1und b2Dateien im aktuellen Verzeichnis, Der [Befehl erhalten würden 9 Argumente: [, b1, b2, =, x, ==,z1 , z2und ].

[analysiert seine Argumente als bedingten Ausdruck. Diese 9 Argumente ergeben keinen gültigen Bedingungsausdruck, sodass wahrscheinlich ein Fehler zurückgegeben wird.

Das [[ ... ]]Konstrukt wurde wahrscheinlich um 1988 von der Korn-Shell eingeführt, da es ksh86a1987 noch nicht vorhanden warksh88 .

Neben ksh (alle Implementierungen) [[...]]wird auch bash (seit Version 2.02) und zsh unterstützt, aber alle drei Implementierungen unterscheiden sich und es gibt Unterschiede zwischen den Versionen derselben Shell, obwohl die Änderungen im Allgemeinen abwärtskompatibel sind (eine bemerkenswerte Ausnahme ist bash) =~Operator, von dem bekannt ist, dass er nach einer bestimmten Version einige Skripte abbricht, wenn sich sein Verhalten ändert). [[...]]wird nicht von POSIX oder Unix oder Linux (LSB) angegeben. Es wurde ein paarmal für die Aufnahme in Betracht gezogen, aber nicht aufgenommen, da die von den Haupt-Shells unterstützte gemeinsame Funktionalität des [Befehls und des Befehls bereits abgedeckt istcase-in-esac Konstrukt .

Das ganze [[ ... ]]Konstrukt bildet einen Befehl. Das heißt, es hat einen Beendigungsstatus (der das wichtigste Asset ist, da er das Ergebnis der Auswertung des bedingten Ausdrucks ist). Sie können ihn an einen anderen Befehl weiterleiten (obwohl dies nicht sinnvoll wäre) und ihn im Allgemeinen überall dort verwenden, wo Sie möchten Verwenden Sie einen beliebigen anderen Befehl (nur innerhalb der Shell, da es sich um ein Shell-Konstrukt handelt), der jedoch nicht wie ein normaler einfacher Befehl analysiert wird. Was sich im Inneren befindet, wird von der Shell analysiert als Bedingungsausdruck und die üblichen Regeln für die Wortteilung und die Generierung von Dateinamen gelten unterschiedlich.

[[ ... ]]weiß ==von Anfang an Bescheid und entspricht =1 . Ein Fehler von ksh (der Verwirrung stiftet und viele Fehler verursacht) ist, dass =und ==kein Gleichheitsoperator, sondern ein Mustervergleichsoperator sind (obwohl der Übereinstimmungsaspekt durch Anführungszeichen deaktiviert werden kann, aber mit unklaren Regeln, die sich von Shell zu Shell unterscheiden).

In Ihrem obigen Code [[ $a == z* ]]würde die Shell das in mehrere Token in ähnlichen Regeln zerlegen, es als Mustervergleich erkennen und als Muster behandeln z*, das mit dem Inhalt der aVariablen abgeglichen werden soll.

Im Allgemeinen ist es schwieriger, sich in den Fuß zu schießen, [[ ... ]]als mit dem [Befehl. Aber ein paar Regeln mögen

  • zitiere immer Variablen
  • nie verwenden -aoder -oOperator (mehrere verwenden [Befehle und die &&und || Shell - Operatoren)

Machen Sie [zuverlässig mit POSIX-Shells.

[[...]]In verschiedenen Shells werden zusätzliche Operatoren unterstützt -nt, z. B. reguläre Ausdrücke für passende Operatoren. Die Liste und das Verhalten variieren jedoch von Shell zu Shell und von Version zu Version.

Wenn Sie also nicht wissen, von welcher Shell und welcher Mindestversion Ihr Skript jemals interpretiert wird, ist es wahrscheinlich sicherer, sich an den Standardbefehl zu halten [.


1 Eine Ausnahme: [[...]]wurde hinzugefügt, um in der Version zu schlagen 2.02. Bis dahin, 2.03wo es geändert wurde, [[ x = '?' ]]würde true zurückgeben, während [[ x == '?' ]]false zurückgegeben würde. Das bedeutet, dass das Zitieren den Mustervergleich nicht verhinderte, wenn der =Operator in diesen Versionen verwendet wurde, sondern wenn ==.

Stéphane Chazelas
quelle
Tolle Infos. Würden Sie bitte erklären, warum "niemals den Operator -a oder -o verwenden"?
Grebneke
@grebneke, versuchen [ '!' = foo -o a = a ]in bashzum Beispiel.
Stéphane Chazelas
0

Beide werden zum Auswerten von Ausdrücken verwendet und funktionieren nicht mit POSIX älteren Bourn-Shell und [[unterstützt auch Pattern Matching und Regex. Beispiel versuchen diese

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"

harish.venkat
quelle
Beachten Sie, dass die Bourne-Shell kein POSIX-Shell ist [[...]]und nur in einigen Versionen einiger Shells reguläre Ausdrücke unterstützt, genau wie einige Versionen von [do den regulären Ausdrücke-Abgleich unterstützen. Zum arithmetischen Vergleich [[schreiben Sie in den unterstützten Shells lieber(( n == 0 && y == 0))
Stéphane Chazelas,