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 [
?
[
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.[
ist ein Befehl.[
ist ein Befehlsname wiecat
oderecho
.[
(wieecho
) 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 estype -a [
in Bash, um das herauszufinden.[
erfordert ein Leerzeichen danach.Als Befehl
[
nimmt Argumente an. Wie bei jedem anderen Befehl müssen die Argumente voneinander und vom Befehlsnamen getrennt werden.[foo
ist ein anderer Befehlsname, ist es nicht gleichwertig mit[ foo
(ebenso und offensichtlicherechoHello world
ist es nichtecho Hello world
). Sie benötigen auf jeden Fall ein Leerzeichen (oder einen Tabulator) nach[
.[
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.[
ist (fast) wietest
.[ … ]
ist gleichbedeutend mittest …
. Mit anderen Worten: Sie können jeden[
Befehl in einentest
Befehl umwandeln, indem Sie das entfernen]
und den Befehlsnamen ändern. Und Sie können jedentest
Befehl in einen[
Befehl umwandeln, indem Sie den Befehlsnamen ändern und hinzufügen]
.[
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 (test
oderecho
,ls
usw.) 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 wiecommand1 || command2
.
[
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-o
er veraltet ist, ist eine bessere Lösung[ … ] || [ … ]
. - Implementierungen unterstützen möglicherweise mehr Primärschlüssel. Die
[
integrierte Bash-Datei tut dies (siehehelp test
); die[
Binärdatei (wie/bin/[
) in Ihrem Betriebssystem unterstützt möglicherweise (sieheman test
).
- Einige Primärcodes sind Erweiterungen, andere sind als veraltet gekennzeichnet. Unser ungültiger Code (
Was ist [[
? Worin besteht [[
der Unterschied zu [
?
Hinweise:
- Die Frage ist markiertSchlag, jetzt reden wir über[[
in Bash.
– Die nummerierten Absätze in diesem Abschnitt entsprechen den nummerierten Absätzen im vorherigen Abschnitt.
(Ä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.(Unterschied)
[[
ist ein Schlüsselwort.ist
[[
ein Shell-Schlüsselwort (rufen Sie estype [[
in Bash auf[
, um dies zu bestätigen). Wie das eingebaute[[
Schlüsselwort gehört es zu Bash; aber esnichtverhalte dich wie ein Befehl.(Ähnlichkeit)
[[
erfordert ein Leerzeichen danach.(Oder eine Registerkarte).
(Ä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]]
.(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 wietest
„can replace“[
.(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 odertest
(oderecho
usw.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[[ … ]] || [[ … ]]
.
(Unterschied)
[[
wird von POSIX nicht spezifiziert.ist
[[
nicht portierbar.[[
funktioniert in Bash, nicht in puresh
. 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üllentest
. 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:
Weder
[
noch[[
ist Teil derif … then …
Syntax. Denken Sie daran,if
dass nur der Beendigungsstatus eines Codes getestet wird.if true; then …
ist gültig,if sleep 5; then …
ist gültig, ähnlichif [ … ]; then …
oderif [[ … ]]; 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 esif
auch danach verwendet werden.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.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. Egfind … -exec [ … ] …
verwendet die ausführbare Datei. Es gibt keine standardmäßige[[
ausführbare Datei (zumindest in den Systemen, die ich kenne), alsofind … -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 [].