Antworten:
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:
[[ … ]]
bedingte Konstrukt um den bedingten Ausdruck $a == z*
.==
Binäroperator mit den Operanden $a
und z*
.a
.==
Operator: Testen Sie, ob der Wert der Variablen a
mit dem Muster übereinstimmt z*
.So [ $a == z* ]
wird bewertet:
[
Befehl mit den Argumenten , die durch die Worte Auswertung $a
, ==
, z*
, ]
.$a
den Wert der Variablen a
.a
ist 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
, ]
.[
mit den im vorherigen Schritt erhaltenen Parametern aus.
[
meldet der Befehl einen Syntaxfehler und gibt den Status 2 zurück.Hinweis: In [[ $a == z* ]]
Schritt 3 wird der Wert von a
keiner 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 a
Platzhalter enthält, a
wird er mit dem Platzhaltermuster abgeglichen. Wenn beispielsweise der Wert von a
ist, 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 $a
nicht übereinstimmen bc
). Innen [[ … ]]
, doppelte Anführungszeichen keinen Unterschied machen, außer auf der rechten Seite der String - Matching Operatoren ( =
, ==
, !=
und =~
).
[
ist ein Alias für den test
Befehl. 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 test
Befehl hinzu , der die meisten der Befehle ausführte "tests", die vom if
Kommando 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, sh
die auf der Almquist-Shell basieren (ein test
Builtin war immer in ash
der 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, $a
da 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 $a
ist b* = x
, und es gibt z1
, z2
, b1
und b2
Dateien im aktuellen Verzeichnis, Der [
Befehl erhalten würden 9 Argumente: [
, b1
, b2
, =
, x
, ==
,z1
, z2
und ]
.
[
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 ksh86a
1987 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 a
Variablen 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
-a
oder -o
Operator (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.03
wo 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 ==
.
[ '!' = foo -o a = a ]
in bash
zum Beispiel.
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"
[[...]]
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))