Ich habe gelesen, dass Sie doppelte Anführungszeichen zum Erweitern von Variablen benötigen, z
if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi
wird wie erwartet funktionieren, während
if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi
wird immer sagen, $test ok
auch wenn $test
null ist.
aber warum brauchen wir dann keine Anführungszeichen echo $test
?
echo
angeben, die als Argument verwendet werden soll, werden zusätzliche Leerzeichen und Zeilenumbrüche entfernt.Antworten:
Sie immer Anführungszeichen um Variablen in allen brauchen Liste Kontexten, die überall die Variable kann auf mehrere Werte erweitert werden , wenn Sie die 3 Nebenwirkungen des Ausscheidens eine variable unquoted wollen.
Liste Kontexte umfassen Argumente einfache Befehle wie
[
oderecho
, diefor i in <here>
Zuweisungen zu Arrays ... Es gibt andere Kontexte , in denen Variablen auch zitiert werden müssen. Am besten zitieren Sie Variablen immer, es sei denn, Sie haben einen guten Grund, dies nicht zu tun.Stellen Sie sich das Fehlen von Anführungszeichen (in Listenkontexten) als den Operator split + glob vor .
Als ob
echo $test
warecho glob(split("$test"))
.Das Shell-Verhalten ist für die meisten Leute verwirrend, weil Sie in den meisten anderen Sprachen feste Zeichenfolgen in Anführungszeichen setzen
puts("foo")
und nicht Variablen (wieputs(var)
), während es in der Shell umgekehrt ist: Alles ist Zeichenfolge in der Shell, also Anführungszeichen um alles wäre umständlich, duecho test
musst nicht"echo" "test"
. In der Shell werden Anführungszeichen für etwas anderes verwendet: Verhindern Sie eine spezielle Bedeutung einiger Zeichen und / oder beeinflussen Sie das Verhalten einiger Erweiterungen.In
[ -n $test ]
oderecho $test
wird die Shell geteilt$test
(standardmäßig in Leerzeichen) und anschließend die Dateinamengenerierung ausgeführt (alle*
Muster '?' ... in die Liste der übereinstimmenden Dateien einblenden) und diese Liste der Argumente an die Befehle[
oder übergebenecho
.Betrachten Sie es erneut als
"[" "-n" glob(split("$test")) "]"
. Wenn$test
leer oder enthält nur Leerzeichen (spc, Tab, nl), dann wird die Split + glob Operator eine leere Liste zurück, so das[ -n $test ]
sein wird"[" "-n" "]"
, das ist ein Test, um zu überprüfen wheter „-n“ die leere Zeichenkette ist oder nicht. Aber stellen Sie sich vor, was passiert wäre, wenn$test
"*" oder "= foo" wäre ...In
[ -n "$test" ]
,[
wird die vier Argumente übergeben"["
,"-n"
,""
und"]"
(ohne die Anführungszeichen), das ist , was wir wollen.Ob es
echo
oder[
keinen Unterschied macht, dann ist es nur , dassecho
Ausgänge die gleiche Sache , ob es ein leeres Argument oder kein Argument überhaupt übergeben wird .Siehe auch diese Antwort auf eine ähnliche Frage für weitere Details zum
[
Befehl und zum[[...]]
Konstrukt.quelle
@ h3rrmillers Antwort ist gut, um zu erklären, warum Sie die Anführungszeichen für
if
(oder besser gesagt,[
/test
) benötigen , aber ich würde tatsächlich annehmen, dass Ihre Frage falsch ist.Probieren Sie die folgenden Befehle aus, und Sie werden sehen, was ich meine.
Ohne die Anführungszeichen bewirkt die Variablensubstitution, dass der zweite Befehl wie folgt erweitert wird:
und die mehreren Leerzeichen werden zu einem einzigen zusammengefasst:
Bei den Anführungszeichen bleiben die Leerzeichen erhalten.
Dies geschieht , weil , wenn Sie einen Parameter zitieren (ob diese Parameter übergeben wird
echo
,test
oder ein anderer Befehl), wird der Wert dieses Parameters als gesendet wird , einen Wert an den Befehl. Wenn Sie es nicht zitieren, sucht die Shell wie gewohnt nach Leerzeichen, um zu bestimmen, wo die einzelnen Parameter beginnen und enden.Dies kann auch durch das folgende (sehr sehr einfache) C-Programm veranschaulicht werden. Versuchen Sie Folgendes in der Befehlszeile (möglicherweise möchten Sie dies in einem leeren Verzeichnis tun, um nicht zu riskieren, etwas zu überschreiben).
und dann...
Nach dem Laufen
paramtest
,$?
wird die Anzahl der Parameter halten , wurde übergeben (und diese Zahl wird gedruckt).quelle
Hier geht es darum, wie die Shell die Zeile interpretiert, bevor ein Programm ausgeführt wird.
Wenn die Zeile lautet
echo I am $USER
, erweitert die Shell sieecho I am blrfl
undecho
hat keine Ahnung, ob der Ursprung des Texts ein Literal oder eine variable Erweiterung ist. In ähnlicher Weise wirdecho I am $UNDEFINED
die Shell beim Lesen einer Zeile$UNDEFINED
in nichts expandieren und die Argumente von echo werdenI am
, und das ist das Ende davon. Daecho
funktioniert ganz gut ohne Argumente,echo $UNDEFINED
ist völlig gültig.Ihr Problem mit
if
ist nicht wirklich mitif
, daif
nur das darauf folgende Programm und die darauf folgenden Argumente ausgeführt werden und derthen
Teil ausgeführt wird, wenn das Programm beendet wird0
(oder derelse
Teil, wenn einer vorhanden ist und das Programm nicht beendet wird0
):Wenn Sie
if [ ... ]
einen Vergleich durchführen, verwenden Sie keine in die Shell eingebauten Grundelemente. Sie weisen die Shell tatsächlich an, ein Programm auszuführen, das aufgerufen[
wird. Dies ist eine sehr geringfügige Obermengetest(1)
dessen letztes Argument sein muss]
. Beide Programme werden beendet,0
wenn die Testbedingung erfüllt ist und1
nicht.Der Grund, warum einige Tests abgebrochen werden, wenn eine Variable undefiniert ist,
test
liegt darin, dass Sie nicht erkennen, dass Sie eine Variable verwenden. Ergo,[ $UNDEFINED -eq 2 ]
bricht ab, weil bis die Shell fertig ist, alletest
nach Argumenten suchen-eq 2 ]
, was kein gültiger Test ist. Wenn Sie dies mit einer definierten Methode tun[ $DEFINED -ne 0 ]
würden , wie z. B. , würde dies funktionieren, da die Shell es zu einem gültigen Test (z0 -ne 0
. B. ) erweitern würde.Es gibt einen semantischen Unterschied zwischen
foo $UNDEFINED bar
, der sich zu zwei Argumenten (foo
undbar
) erweitert, weil$UNDEFINED
er seinem Namen gerecht wurde. Vergleichen Sie dies mitfoo "$UNDEFINED" bar
, was sich auf drei Argumente (foo
eine leere Zeichenkette und einen Balken) erweitert. Anführungszeichen zwingen die Shell, sie als Argument zu interpretieren, ob sich etwas zwischen ihnen befindet oder nicht.quelle
Ohne Anführungszeichen
$test
kann es zu mehr als einem Wort kommen, daher muss es in Anführungszeichen gesetzt werden, um die Syntax nicht zu brechen, da jeder Schalter innerhalb des[
Befehls ein Argument erwartet, was die Anführungszeichen bewirken (alles wird$test
zu einem Argument erweitert).Der Grund, warum Sie keine Anführungszeichen benötigen, um eine Variable mit zu erweitern,
echo
ist, dass sie kein einziges Argument erwartet. Es wird einfach gedruckt, was Sie ihm sagen. Selbst wenn$test
das Echo auf 100 Wörter erweitert wird, wird es trotzdem gedruckt.Schauen Sie sich Bash Pitfalls an
quelle
echo
?echo
. Was lässt dich anders denken?echo $test
und es funktioniert (es gibt den Wert von $ test)Leere Parameter werden entfernt, wenn sie nicht in Anführungszeichen gesetzt werden:
Der aufgerufene Befehl erkennt nicht, dass in der Shell-Befehlszeile ein leerer Parameter vorhanden ist. Es scheint, dass [definiert ist, um 0 für -n zurückzugeben, ohne dass etwas folgt. Warum auch immer.
Zitate wirken sich in einigen Fällen auch auf das Echo aus:
quelle
echo
die Muschel. Sie würden das gleiche Verhalten mit sehenls
. Probierentouch '*'
Sie es aus, wenn Sie sich abenteuerlustig fühlen.:)