Unterschied zwischen [[ ]] UND [ ] oder (( )) UND ( ) in Bash

Unterschied zwischen [[ ]] UND [ ] oder (( )) UND ( ) in Bash

Was ist der Unterschied zwischen der Verwendung von [[ condition ]]und [ condition ]oder (( condition ))und ( condition )? In welchem ​​Szenario müssen wir eines von beiden verwenden?

  • (( 10 > 9 ))funktioniert, aber (( 10 -gt 9 ))nicht
  • [[ 10 -gt 9 ]]funktioniert, aber [[ 10 > 9 ]]nicht

Antwort1

((...))ist die SchaleArithmetikkonstruieren. Die Operatoren, die Sie verwenden können, sind im Handbuch dokumentiert:6.5 Schalenarithmetik

(...)ist einGruppierungKonstrukt, das die enthaltenen Befehle in einer Subshell ausführt:3.2.4.3 Gruppierungsbefehle

[...]ist die „alte“ Bedingungskonstruktion. Die Dokumentation finden Sie unter6.4 Bedingte Ausdrücke in Bash

[[...]]macht alles, was auch [...]immer. Der Unterschied besteht darin, dass Wortaufteilung und Glob-Erweiterung für darin enthaltene Variablen nicht durchgeführt werden, [[...]]sodass das Anführen der Variablen nicht so wichtig ist. Außerdem [[kannMustervergleichmit dem ==Betreiber undÜbereinstimmung mit regulären Ausdrückenmit dem =~Betreiber.

Der Grund [[ 10 > 9 ]]für das unerwartete Ergebnis liegt darin, dass der >Operator darin [[...]]fürZeichenfolgenvergleichund die Zeichenfolge „10“ ist „kleiner als“ die Zeichenfolge „9“.

Antwort2

Über ((…))und(…)

Wie angegeben indiese andere Antwort((…))ist das arithmetische Konstrukt der Shell ( einBashismus) und (…)führt Befehle in einer Subshell aus. Sie unterscheiden sich stark voneinander und von [ … ]oder [[ … ]].

Andererseits sind [ … ]und [[ … ]]in einfachen Fällen sehr ähnlich; sie können verwechselt werden. Der Rest dieser Antwort konzentriert sich auf [ … ]und [[ … ]].


Formelle Anmerkung

Meine Ziele hier sind:

  • näher erläuternUnterschiede und Ähnlichkeiten zwischen [ … ]und[[ … ]];
  • um eine kanonische Antwort im Betreff von [ … ]vs bereitzustellen, sodass Fragen, die mit „ ist nicht “ [[ … ]]beantwortet werden können, hierher verlinkt werden können;[[[
  • um eine ausreichend umfassende Antwort zu geben, sodass Benutzer nicht länger in Versuchung geraten, Antworten zu posten, die sich jeweils auf einen einzigen Unterschied konzentrieren.

Was ist [?

  1. [führt einen Test durch.

    Der Zweck [besteht darin, etwas zu testen (z. B. ob eine Datei vorhanden ist) und den Beendigungsstatus Null zurückzugeben, wenn der Test erfolgreich war, andernfalls einen Wert ungleich Null.

  2. [ist ein Befehl.

    [ist ein Befehlsname wie catoder echo. [(wie echo) ist in Bash integriert, aber das bedeutet nur, dass es ausgeführt werden kann, ohne einen zusätzlichen Prozess zu starten, es verhält sich trotzdem wie ein Befehl. [In Ihrem System gibt es wahrscheinlich eine eigenständige ausführbare Datei (z. B. /bin/[); versuchen Sie es type -a [in Bash, um das herauszufinden.

  3. [erfordert ein Leerzeichen danach.

    Als Befehl [nimmt Argumente an. Wie bei jedem anderen Befehl müssen die Argumente voneinander und vom Befehlsnamen getrennt werden. [fooist ein anderer Befehlsname, ist es nicht gleichwertig mit [ foo(ebenso und offensichtlicher echoHello worldist es nicht echo Hello world). Sie benötigen auf jeden Fall ein Leerzeichen (oder einen Tabulator) nach [.

  4. [erfordert ].

    [erfordert ]als letztes Argument, sonst funktioniert es nicht. Dies dient nur dazu, es [ … ]als Block hervorzuheben, als wäre es eine spezielle Syntax; es ist aber keine spezielle Syntax. Um es ]als letztes Argument zu übergeben, benötigen Sie ein Leerzeichen (oder einen Tabulator) davor. Zum Vergleich: Das letzte Argument in [ … bar]ist , bar]was nicht ist ]und daher [ … bar]kein gültiger Befehl ist.

  5. [ist (fast) wie test.

    [ … ]ist gleichbedeutend mit test …. Mit anderen Worten: Sie können jeden [Befehl in einen testBefehl umwandeln, indem Sie das entfernen ]und den Befehlsnamen ändern. Und Sie können jeden testBefehl in einen [Befehl umwandeln, indem Sie den Befehlsnamen ändern und hinzufügen ].

  6. [ist nichts Besonderes.

    Es ist gut, sich daran zu erinnern [, dass es nichts Besonderes ist, sondern nur ein etwas ausgefallener Name für einen Befehl. Wenn Sie dies berücksichtigen, werden Sie nicht überrascht sein, dassalledas Parsen und Verarbeiten der ShellVorDas Ausführen eines Befehls ( testoder echo, lsusw.) erfolgt auch, wenn der Befehl ist [. Insbesondere:

    • [ist sich nicht bewusst, ob Sie eines seiner Argumente in Anführungszeichen gesetzt haben; es erhält die Argumente, nachdem die Shell die Anführungszeichen entfernt hat.

    • Ohne Anführungszeichen und ohne Escapezeichen &&oder ||zwischen [und ]wird nicht als Argument für interpretiert [. Mit anderen Worten [ … || … ]wird interpretiert als [ …(ungültig, da kein vorhanden ist ]) und … ](ein separater Befehl, was auch immer ) logisch verbunden mit ||, genau wie command1 || command2.

  7. [wird durch POSIX spezifiziert.

    Dort ist derPOSIX-Spezifikation für [/test. Sie können [portabel anrufen. Hinweise:

    • Einige Primärcodes sind Erweiterungen, andere sind als veraltet gekennzeichnet. Unser ungültiger Code ( [ … || … ]) kann beispielsweise als behoben werden [ … -o … ], aber da -oer veraltet ist, ist eine bessere Lösung [ … ] || [ … ].
    • Implementierungen unterstützen möglicherweise mehr Primärschlüssel. Die [integrierte Bash-Datei tut dies (siehe help test); die [Binärdatei (wie /bin/[) in Ihrem Betriebssystem unterstützt möglicherweise (siehe man test).

Was ist [[? Worin besteht [[der Unterschied zu [?

Hinweise:
- Die Frage ist markiert, jetzt reden wir über[[ in Bash.
– Die nummerierten Absätze in diesem Abschnitt entsprechen den nummerierten Absätzen im vorherigen Abschnitt.

  1. (Ähnlichkeit)[[führt einen Test durch.

    Der Zweck [[besteht darin, etwas zu testen (z. B. ob eine Datei vorhanden ist) und den Beendigungsstatus Null zurückzugeben, wenn der Test erfolgreich war, andernfalls ungleich Null. [[kann alles testen [, was kann, und mehr.

  2. (Unterschied)[[ist ein Schlüsselwort.

    ist[[ ein Shell-Schlüsselwort (rufen Sie es type [[in Bash auf [, um dies zu bestätigen). Wie das eingebaute [[Schlüsselwort gehört es zu Bash; aber esnichtverhalte dich wie ein Befehl.

  3. (Ähnlichkeit)[[erfordert ein Leerzeichen danach.

    (Oder eine Registerkarte).

  4. (Ähnlichkeit)[[erfordert ]].

    [[erfordert ]]später im Code, es dient jedoch nicht nur dazu, [[ … ]]als Block hervorgehoben zu werden. Es handelt sich um eine spezielle Syntax (ein Unterschied, wir werden darauf zurückkommen). Sie benötigen ein Leerzeichen (oder einen Tabulator) vor ]].

  5. (Unterschied)Es gibt keinen normal aussehenden Befehl, der dem entspricht [[.

    Es gibt keinen anderen Befehl/Schlüsselwort/was auch immer, das [[auf die gleiche Weise ersetzen kann wie test„can replace“ [.

  6. (Unterschied)[[ Istbesonders.

    [[ändert die Art und Weise, wie die Shell den Code analysiert und interpretiert, bis hin zum passenden ]]. Das normale Parsen und Verarbeiten, das die Shell vor dem Ausführen [von oder test(oder echousw. ls) durchführt, gilt innerhalb von nicht [[ … ]]. Insbesondere:

    • [[ Istbewusst, ob Sie eines seiner "Argumente" zitiert haben. Das doppelte Anführen von Variablen ist nicht notwendig (während normalerweisees ist), aber in manchen Fällen macht die doppelte Anführungszeichensetzung eines Strings (oder einer Variablen) einen Unterschied (siehediese Antwortwo es heißt „die rechte Seite von =oder ==oder !=oder =~“)

    • &&oder ||zwischen [[und ]]gehört zur [[ … ]]Konstrukt. [[ … || … ]]kann ein gültiger Codeabschnitt sein, praktisch gleichwertig mit [[ … ]] || [[ … ]].

  7. (Unterschied)[[wird von POSIX nicht spezifiziert.

    ​ist[[ nicht portierbar. [[funktioniert in Bash, nicht in pure sh. Andere Shells unterstützen dies möglicherweise [[(z. B. Zsh), aber ihre können sich von denen von Bash [[unterscheiden .[[

    [[[ist nicht darauf ausgelegt, die Spezifikation von / zu erfüllen test. In vielen Fällen erhalten Sie durch Ersetzen [von mit [[und ]durch einen Snippet, der dem ursprünglichen Snippet entspricht; aber nicht immer,]][[ … ]][ … ]Manchmaldas Innere muss angepasst werden. Ändern Sie also nicht blind [zu [[. Blindes Ändern [[zu [ist noch riskanter, da es Tests gibt, die [[ausgeführt werden können, während [dies nicht möglich ist.


Weitere Hinweise:

  1. Weder [noch [[ist Teil der if … then …Syntax. Denken Sie daran, ifdass nur der Beendigungsstatus eines Codes getestet wird. if true; then …ist gültig, if sleep 5; then …ist gültig, ähnlich if [ … ]; then …oder if [[ … ]]; then …ist gültig (wenn der [ … ]oder [[ … ]]Teil selbst ein gültiger Codeausschnitt ist).

    Da ((…))„or“ (…)auch einen Beendigungsstatus zurückgibt (der vom Inhalt abhängt), kann es ifauch danach verwendet werden.

  2. Persönlich bevorzuge ich [für alle Tests die Verwendung von [, die sich problemlos durchführen lässt, und greife nur auf zurück, [[wenn es wirklich nötig ist. Auf diese Weise gewöhne ich mich nicht an nicht portable Umgebungen [[und weiß, was ich in einer Shell tun kann, die nicht so umfangreich ist wie Bash.

  3. Die [ausführbare Datei in Ihrem Betriebssystem ist nicht unbedingt genau gleichbedeutend mit der [integrierten Datei in Ihrer Bash. Wenn [sie von Bash aufgerufen wird, erledigt die integrierte Datei die Aufgabe. Wenn [sie von etwas anderem aufgerufen wird, erledigt die ausführbare Datei die Aufgabe. Eg find … -exec [ … ] …verwendet die ausführbare Datei. Es gibt keine standardmäßige [[ausführbare Datei (zumindest in den Systemen, die ich kenne), also find … -exec [[ … ]] …wird es nie funktionieren. Wenn es eine [[ausführbare Datei gäbe, müsste sie sich wie ein Befehl verhalten und könnte das Schlüsselwort nicht nachahmen.

Antwort3

Es gibt einen großen Unterschied zwischen [ ] und [[ ]]:

a=0;
if [ $a = 1 -a $(grep ERR 1.log|wc -l) -ne 0 ];then
      echo "error";
fi 

Bei Verwendung von [ ] unterstützt der Operator -a keine Kurzschlussauswertung. Im obigen Code wird die zweite Bedingung trotzdem ausgewertet, auch wenn die erste Bedingung „false“ zurückgibt. Wenn die Datei 1.log nicht existiert, wird die Meldung „Keine solche Datei oder kein solches Verzeichnis“ ausgegeben.

Aber für [[ ]]:

a=0
if [[ $a = 1 && $(grep ERR 1.log|wc -l) -ne 0 ];then
    echo "error"
fi

selbst wenn die Datei „1.log“ nicht existiert, ist alles in Ordnung, weil die zweite Bedingung nicht ausgewertet wird, da die erste Bedingung falsch ist.

Antwort4

Ich hätte dies in einen Kommentar geschrieben, darf dies aber derzeit nicht.

Ein Unterschied, der mir zwischen [] und [[]] aufgefallen ist, besteht darin, dass bei ersterem mehrere Vergleiche möglich sind.

Der gleiche Vergleich wirft einen Syntaxfehler in [[]]

a=1
b=2

Das funktioniert:

$  [ "$a" -gt 0 -a "$b" -gt "$a" ] && { echo '[b>a>0]'; }
[b>a>0]

Das funktioniert nicht:

$ [[ $a -gt 0 -a $b -gt $a ]] && { echo '[[b>a>0]]'; }
-bash: syntax error in conditional expression
-bash: syntax error near `-a'

Ich habe mich noch nicht wirklich damit befasst, warum das so ist, aber bei Mehrfachvergleichen verwende ich [].

verwandte Informationen