Warum doppelte Anführungszeichen in einem [[]] Test verwenden?

23

Nehmen wir an, wir haben zwei Ganzzahlen in einem Bash-Skript:

value1=5
value2=3

Warum müssen wir dann im Falle eines Tests doppelte Anführungszeichen verwenden? Beispielsweise:

if [[ "$value1" -eq "$value2" ]]

Warum nicht einfach folgendes verwenden?

if [[ $value1 -eq $value2 ]]

Für mich machen die doppelten Anführungszeichen keinen Sinn.

Erdmännchen
quelle
5
Zitiert in der Schale hat wenig mit Saiten zu tun , es geht wirklich um die Schale zu verhindern , dass einzelne Wörter aufgespalten Durchführung (wie in Datentypen.) (Und andere Arten von Erweiterungen.)
filbranden
13
Während es, wie Terdon betonte, nicht notwendig ist, Variablen in diesem speziellen Konstrukt zu zitieren (und natürlich überall mit Ein-Wort-Werten), möchte ich den Rat geben, immer Ihre Variablen zu zitieren . Wissen Sie wirklich, in welchen Kontexten Sie Variablen ohne Anführungszeichen lassen können? Der Grund überhaupt zu zitieren, auch wenn es nicht mit 5und notwendig ist 3, ist Wartbarkeit. Die Werte können sich später ändern und die daraus resultierenden Fehler sind möglicherweise nicht offensichtlich.
Peter - Setzen Sie Monica
2
@sudodus Ich glaube nicht, dass das wahr ist [[ ]], nur für [ ].
Benjamin W.
1
Du hast recht, @BenjaminW. Die Wortteilung ist nicht der einzige Grund, weshalb die Verwendung von Anführungszeichen für Variablen sinnvoll ist. Es ist auch der Fall, wenn eine Variable leer ist. Dies führt dazu, dass die Anweisung in [] fehlschlägt (zum Beispiel [2 -eq] mit einem Fehler, aber [[]] ist nicht anfällig (wie im Fall der Wortteilung).
sudodus
2
@marcelm, Bash, ksh und Zsh haben ganzzahlige Variablen, und innerhalb [[ ]]dieser Variablen werden auch die Operanden -eqin ganze Zahlen umgewandelt.
ilkkachu

Antworten:

7

Wortteilung.

Dieses Beispiel ist sehr unwahrscheinlich, aber möglich . Wenn Sie also defensiv codieren möchten, müssen Sie Ihre Tracks mit Anführungszeichen versehen:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

OK, soweit alles gut. Lassen Sie uns den Schraubenschlüssel in die Zahnräder werfen:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

Hoppla.

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

Ahh.

Glenn Jackman
quelle
2
OP verwendet jedoch doppelte Klammern, sodass keine Wortteilung stattfindet.
user000001
5
Ja, das ist für bashs [[ ]]Konstrukt nicht wirklich relevant .
Terdon
1
Wie? [ $value1 -eq $value2 ]mit einem leeren value1wäre '[' -eq 3 ']'mit nein ''auf der linken Seite.
Charles Duffy
Ich war auch überrascht, aber es gibt Beweise.
Glenn Jackman
1
Diese Antwort bezieht sich nicht direkt auf die Frage. Ich bin überrascht, dass es akzeptiert wurde. Einstellung als Community-Wiki.
Glenn Jackman
35

Die Anführungszeichen brauchen Sie hier eigentlich nicht. Dies ist einer der wenigen Fälle, in denen es sicher ist, eine Variable ohne Anführungszeichen zu verwenden. Sie können dies bestätigen mit set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

Wie Sie oben sehen können, werden die zitierten und nicht zitierten Versionen des Tests durch Bash genau gleich aufgelöst. Das Gleiche sollte für zshjede andere Shell gelten, die den [[ ]]Operator unterstützt .

Beachten Sie, dass dies bei tragbaren Geräten nicht der Fall ist [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

Das [ ]Konstrukt [[ ]]erfordert im Gegensatz zu dem einen ein Zitieren.


Einige nützliche Links, um mehr darüber zu erfahren, wann und warum ein Angebot erforderlich ist:

terdon
quelle
In diesem Fall ist es bei ganzzahligen Variablen besser, sie als solche zu deklarieren. declare -i var1=ist 0bei der Auswertung.
Freddy
4
Beachten Sie, dass dies -eqein arithmetischer Vergleich ist, sodass Sie sogar das $Auslassen (Einlassen [[ .. ]]) und Schreiben ausführen können [[ a -eq b ]]. Beim Stringvergleich brauchst du $natürlich das[[ $a = $b ]]
ilkkachu
2
@ user000001 guter Punkt. Obwohl es natürlich sehr gut möglich ist, dass Sie diese erweitern möchten . Zum Beispiel würde ich erwarten , dass dies ein Spiel sein: var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. Wenn Sie die Glob-Zeichen verwenden möchten, ohne dass sie in einem Glob-Kontext (z. B. dem [[ ]]) als Glob fungieren , müssen Sie sie in Anführungszeichen setzen, ja.
Terdon
3
@ilkkachu, das überrascht mich. Ich dachte, dass "nackte" Variablen nur in einem Array-Index oder ((...))oder berücksichtigt werden $((...). Es scheint zu funktionieren, aber ich mag es nicht.
Glenn Jackman
1
@glennjackman, nun, tut mir leid, dass ich Ihnen das sagen muss, aber ja, die Operanden für -eqund Freunde im Inneren [[ ]]sind auch arithmetische Kontexte. :) (Siehe auch: Automatische Variablenerweiterung innerhalb des Befehls bash [[]] )
ilkkachu
17

Auch wenn die Anführungszeichen nicht erforderlich sind, gibt es folgende Gründe, sie zu verwenden:

  • Gute Praxis / Gewohnheit: In diesem Fall sind sie nicht notwendig, aber im Allgemeinen doppelte Anführungszeichen sind unbeabsichtigtes Wort Spaltung zu vermeiden.
  • Denn value1und value2sind variabel, und Sie wissen möglicherweise nicht, was sie enthalten. Andernfalls könnten Sie genauso gut fragen: "Warum sich mit Variablen beschäftigen anstatt sie zu überprüfen if [[ 5 -eq 3 ]]? Oder noch weiter gehen, warum sich überhaupt um die kümmern, ifwenn Sie bereits wissen, dass 5 nicht gleich 3 ist? Es ist oft besser, defensiv zu sein. (Es ist wahr.) Diese [[Wortspaltung kommt nicht vor , aber Fälle, in denen Wortspaltung nicht vorkommt , sind selten. Siehe auch den ersten Punkt.)
jamesdlin
quelle
1

Nicht direkt im Zusammenhang mit Ihrer Frage, aber ich benutze

if (($ value1 == $ value2)); dann

Wenn ich Zahlen vergleiche, muss man aber auch keine Anführungszeichen verwenden.

framp
quelle
2
if (( value1 == value2 )); then. In arithmetischen Kontexten brauchen Sie nicht einmal die $. Diese Frage scheint sich jedoch auf Variablen zu konzentrieren, die in [[ ... ]]Tests verwendet werden.
Kusalananda
1
Ich kenne. Aber ich benutze diese Funktion ehrlich gesagt nicht, weil ich möchte, dass meine Variablennamen konsistent sind und daher $ die ganze Zeit als Präfix verwenden.
Freitag,
1

Du liegst absolut richtig!

Die Angabe in doppelten eckigen Klammern macht zumindest in diesem Fall überhaupt keinen Sinn.

Aber da ich täglich doppelte Anführungszeichen verwende - insbesondere für einfache eckige Klammern, die Übergabe von Argumenten an Funktionen und Skripten sowie manchmal die Zuweisung von Variablen (was für einfache Delkarationen völlig unbrauchbar ist) - denke ich, dass es zumindest einige Leute gibt, schreiben Sie instinktiv doppelte Anführungszeichen um variable Erweiterungen .

Doppelte Anführungszeichen geben Ihnen ein Gefühl der Sicherheit. Es ist wie nach Hause zu kommen, wo doppelte Anführungszeichen stehen. - D. Kummer

Wenn Sie konsequent und verständlich doppelte Anführungszeichen setzen, haben Sie den Vorteil, dass Kollegen, die noch keine Erfahrung mit Bash haben, lernen können, stabilere Skripte zu schreiben . Dies unterstreicht auch die Tatsache, dass es bei der Datenverarbeitung mit bash mehr darum geht , Datenströme (einschließlich Variablen) durch Feldtrennzeichen zu trennen und durch Filter zu leiten . Sobald Sie Ihre Datenblöcke vom Stream getrennt haben, halten Sie sie mit doppelten Anführungszeichen zusammen!

Ein weiterer Vorteil könnte die bessere Lesbarkeit von Bash-Skripten mit doppelten Anführungszeichen in einem Code-Hervorhebungs-Editor sein .

Dominik Kummer
quelle