Ich bin verwirrt mit einfachen oder doppelten Klammern. Schau dir diesen Code an:
dir="/home/mazimi/VirtualBox VMs"
if [[ -d ${dir} ]]; then
echo "yep"
fi
Es funktioniert perfekt, obwohl die Zeichenfolge ein Leerzeichen enthält. Aber wenn ich es in einzelne Klammer ändere:
dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then
echo "yep"
fi
Es sagt:
./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected
Wenn ich es ändere zu:
dir="/home/mazimi/VirtualBox VMs"
if [ -d "${dir}" ]; then
echo "yep"
fi
Es funktioniert gut. Kann jemand erklären, was passiert? Wann sollte ich Variablen "${var}"
in doppelte Anführungszeichen setzen , um Probleme durch Leerzeichen zu vermeiden?
Antworten:
Die einzelne Klammer
[
ist eigentlich ein Alias für dentest
Befehl, es ist keine Syntax.Einer der Nachteile (von vielen) der einzelnen Klammern ist, dass, wenn einer oder mehrere der Operanden, die ausgewertet werden sollen, eine leere Zeichenfolge zurückgeben, beanstandet wird, dass zwei Operanden (binär) erwartet wurden. Dies ist der Grund, warum Sie Leute sehen
[ x$foo = x$blah ]
, diex
garantieren, dass der Operand niemals eine leere Zeichenkette ergibt .Die doppelte Klammer
[[ ]]
hingegen ist syntaktisch und weitaus leistungsfähiger als[ ]
. Wie Sie herausgefunden haben, gibt es kein einzelnes Operandenproblem und es ermöglicht auch eine C-ähnliche Syntax mit>, <, >=, <=, !=, ==, &&, ||
Operatoren.Meine Empfehlung lautet: Wenn Ihr Dolmetscher ist
#!/bin/bash
, dann immer verwenden[[ ]]
Es ist wichtig zu beachten, dass dies
[[ ]]
nicht von allen POSIX-Shells unterstützt wird, jedoch von vielen Shells wiezsh
undksh
zusätzlich unterstützt wirdbash
quelle
$foo
ist!
oder(
oder-n
... Dieses Problem ist nicht als Problem mit POSIX-Shells gedacht, bei denen die Anzahl der Argumente (neben[
und]
) nicht größer als vier ist.[ x$foo = x$blah ]
ist genauso schlicht falsch wie[ $foo = $bar ]
.[ "$foo" = "$bar" ]
ist in jeder POSIX-kompatiblen Shell korrekt,[ "x$foo" = "x$bar" ]
würde in jeder Bourne-ähnlichen Shell funktionieren, aber dasx
ist nicht für Fälle, in denen Sie leere Zeichenfolgen haben, sondern wo$foo
sein!
oder-n
...[
ist nicht genau ein Pseudonym fürtest
. Wenn dies der Falltest
wäre, würde eine schließende eckige Klammer akzeptiert.test -n foo ]
. Tut estest
aber nicht und[
benötigt eines.[
isttest
in jeder Hinsicht identisch mit , aber soalias
funktioniert das nicht . Bash beschreibt[
undtest
als Shell-Builtins , aber[[
als Shell-Schlüsselwort .>=
und<=
Der
[
Befehl ist ein gewöhnlicher Befehl. Obwohl die meisten Shells dies als integrierte Funktion für die Effizienz bereitstellen, werden die normalen syntaktischen Regeln der Shell eingehalten.[
ist genau gleichbedeutend mittest
, außer dass[
a]
als letztes Argument benötigt wird undtest
nicht.Die doppelten Klammern
[[ … ]]
sind spezielle Syntax. Sie wurden in ksh (einige Jahre später[
) eingeführt, da[
ihre korrekte Verwendung problematisch sein kann und[[
einige neue nette Ergänzungen zulässt, die Shell-Sonderzeichen verwenden. Zum Beispiel können Sie schreibenweil der gesamte Bedingungsausdruck von der Shell analysiert wird, während er
[ $x = foo && $y = bar ]
zuerst in zwei Befehle aufgeteilt[ $x = foo
und$y = bar ]
vom&&
Operator getrennt wird . In ähnlicher Weise ermöglichen doppelte Klammern Dinge wie die Pattern-Matching-Syntax, um z. B.[[ $x == a* ]]
zu testen, ob der Wert von mitx
beginnta
; In einfachen Klammern wird diesa*
auf die Liste der Dateien ausgedehnt, deren Namena
im aktuellen Verzeichnis beginnen. Doppelte Klammern wurden zuerst in ksh eingeführt und sind nur in ksh, bash und zsh verfügbar.In einfachen Klammern müssen Sie Variablen wie an den meisten anderen Stellen in doppelte Anführungszeichen setzen, da es sich nur um Argumente für einen Befehl handelt (der zufällig der
[
Befehl ist). In doppelten Klammern brauchen Sie keine doppelten Anführungszeichen, da die Shell keine Worttrennung oder Globen ausführt: Sie analysiert einen bedingten Ausdruck, keinen Befehl.Eine Ausnahme besteht jedoch darin,
[[ $var1 = "$var2" ]]
dass Sie die Anführungszeichen benötigen, wenn Sie einen Byte-zu-Byte-Vergleich von Zeichenfolgen durchführen$var2
möchten$var1
.Eine Sache, mit der Sie nichts anfangen können,
[[ … ]]
ist die Verwendung einer Variablen als Operator. Dies ist beispielsweise vollkommen legal (aber selten nützlich):In deinem Beispiel
der Befehl innerhalb der
if
ist[
mit den 4 Argumente-d
,/home/mazimi/VirtualBox
,VMs
und]
. Die Shell analysiert-d /home/mazimi/VirtualBox
und weiß dann nicht, was zu tun istVMs
. Sie müssten verhindern, dass sich das Wort aufteilt${dir}
, um einen wohlgeformten Befehl zu erhalten.Verwenden Sie generell immer doppelte Anführungszeichen um Variablen- und Befehlssubstitutionen, es sei denn, Sie wissen, dass Sie das Ergebnis aufteilen und glätten möchten. Die wichtigsten Stellen, an denen es sicher ist, keine doppelten Anführungszeichen zu verwenden, sind:
foo=$bar
(aber beachten Sie, dass Sie die doppelten Anführungszeichen inexport "foo=$bar"
oder in Array-Zuweisungen wie benötigenarray=("$a" "$b")
);case
Aussagecase $foo in …
:;=
oder==
Operator (es sei denn , Sie Pattern - Matching tun wollen):[[ $x = "$y" ]]
.In all diesen Fällen ist es richtig, doppelte Anführungszeichen zu verwenden. Sie können also auch die erweiterten Regeln überspringen und die Anführungszeichen immer wieder verwenden.
quelle
[
es sich in der Tat um System III aus dem Jahr 1981 handelt , ich dachte, es wäre älter.Implizit in dieser Frage ist
${variable_name}
bedeutet nicht, was Sie denken, dass es tut ...... wenn Sie denken , es hat etwas mit Problemen durch Leerzeichen (in Variablenwerte) verursacht zu tun. ist gut dafür:
${variable_name}
und sonst nichts! 1 macht nicht jeder gutwenn Sie sofort sind sie mit einem Zeichen nachdie Teil eines Variablenname sein könnte: ein Brief (-oder-), einen Unterstrich () oder eine Ziffer (-). Und selbst dann können Sie es umgehen:
${variable_name}
A
Z
a
z
_
0
9
Ich versuche nicht, seine Verwendung zu entmutigen -
echo "${bar}d"
ist hier wahrscheinlich die beste Lösung -, sondern Menschen davon abzuhalten, sich auf Klammern anstatt auf Zitate zu verlassen oder Klammern instinktiv anzuwenden und dann zu fragen: „Brauche ich jetzt auch Zitate ? „ Sie sollten immer Anführungszeichen verwenden, es sei denn, Sie haben einen guten Grund, dies nicht zu tun, und Sie sind sicher, dass Sie wissen, was Sie tun._________________
1 Außer natürlich, dass die schickeren Formen der Parametererweiterung , zum Beispiel und , auf der Syntax aufbauen . Außerdem müssen Sie verwenden , etc., die 10., 11. zu referenzieren usw. Positionsparameter - Zitate werden nicht Ihnen dabei helfen.
${parameter:-[word]}
${parameter%[word]}
${parameter}
${10}
${11}
quelle
Um Leerzeichen und Leerzeichen in Variablen zu behandeln, sollten Sie sie immer in doppelte Anführungszeichen setzen. Das Einstellen eines ordnungsgemäßen IFS ist ebenfalls eine gute Praxis.
Empfohlen: http://www.dwheeler.com/essays/filenames-in-shell.html
quelle