Je suis confus d'utiliser des crochets simples ou doubles. Regardez ce code:
dir="/home/mazimi/VirtualBox VMs"
if [[ -d ${dir} ]]; then
echo "yep"
fi
Cela fonctionne parfaitement bien que la chaîne contienne un espace. Mais quand je le change en support unique:
dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then
echo "yep"
fi
Ça dit:
./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected
Quand je le change en:
dir="/home/mazimi/VirtualBox VMs"
if [ -d "${dir}" ]; then
echo "yep"
fi
Ça fonctionne bien. Quelqu'un peut-il expliquer ce qui se passe? Quand devrais-je assigner des guillemets autour des variables "${var}"
pour éviter les problèmes causés par des espaces?
Réponses:
Le crochet unique
[
est en fait un alias pour latest
commande, ce n'est pas une syntaxe.L’un des inconvénients (parmi de nombreux autres) du support unique est que si un ou plusieurs opérandes qu’il essaie d’évaluer renvoient une chaîne vide, il se plaindra du fait qu’il attendait deux opérandes (binaire). C’est la raison pour laquelle vous voyez les gens faire
[ x$foo = x$blah ]
, lesx
garanties que l’opérande ne sera jamais considéré comme une chaîne vide.Le double crochet
[[ ]]
, par contre, est une syntaxe et est beaucoup plus capable que[ ]
. Comme vous l'avez découvert, il n'y a pas de problème d'opérande unique et cela permet également une syntaxe plus semblable à celle du C avec les>, <, >=, <=, !=, ==, &&, ||
opérateurs.Ma recommandation est la suivante: Si votre interprète est
#!/bin/bash
, utilisez toujours[[ ]]
Il est important de noter que
[[ ]]
n'est pas pris en charge par toutes les coquilles POSIX, mais beaucoup de coquilles ne le soutiennent par exemplezsh
etksh
en plusbash
la source
$foo
est!
ou(
ou-n
... Ce problème n'est pas censé être un problème avec les shells POSIX où le nombre d'arguments (à côté de[
et]
) n'est pas supérieur à quatre.[ x$foo = x$blah ]
est tout aussi faux que[ $foo = $bar ]
.[ "$foo" = "$bar" ]
est correct dans une coquille conforme aux spécifications POSIX,[ "x$foo" = "x$bar" ]
travaillerait dans une Bourne shell-like, maisx
n'est pas pour les cas où vous avez des chaînes vides mais où$foo
peut - être!
ou-n
...[
n'est pas précisément un alias pourtest
. Si c'était le cas,test
accepterait un crochet de fermeture.test -n foo ]
. Maistest
ne le fait pas et en[
nécessite un.[
est identique àtest
tous les autres aspects, mais ce n'est pas comme ça que çaalias
marche. Bash décrit[
et entest
tant que shell intégré , mais en[[
tant que mot clé shell .>=
et<=
La
[
commande est une commande ordinaire. Bien que la plupart des shells le fournissent de manière intégrée pour plus d’efficacité, il respecte les règles syntaxiques normales du shell.[
est exactement équivalent àtest
, sauf que[
nécessite un]
comme dernier argument ettest
ne le fait pas.Les doubles crochets
[[ … ]]
sont une syntaxe spéciale. Ils ont été introduits en ksh (plusieurs années après[
), car leur utilisation[
peut être compliquée et[[
autorise de nouveaux ajouts intéressants utilisant des caractères spéciaux du shell. Par exemple, vous pouvez écrireparce que la totalité de l'expression conditionnelle est analysée par le shell, alors qu'elle
[ $x = foo && $y = bar ]
serait d'abord divisée en deux commandes[ $x = foo
et$y = bar ]
séparée par l'&&
opérateur. De même, les doubles crochets permettent des choses comme la syntaxe de correspondance de modèle, par exemple[[ $x == a* ]]
pour vérifier si la valeur dex
commence para
; entre crochets simples, cela étendraita*
la liste des fichiers dont le nom commence para
le répertoire actuel. Les doubles crochets ont été introduits pour la première fois en ksh et ne sont disponibles qu’en ksh, bash et zsh.Entre crochets simples, vous devez utiliser des guillemets doubles autour des substitutions de variables, comme dans la plupart des autres endroits, car ce ne sont que des arguments pour une commande (qui se trouve être la
[
commande). Dans les doubles crochets, vous n'avez pas besoin de guillemets, car le shell ne scinde ni ne sculpte les mots: il analyse une expression conditionnelle, pas une commande.Une exception est toutefois
[[ $var1 = "$var2" ]]
lorsque vous avez besoin des guillemets si vous souhaitez effectuer une comparaison chaîne par octet, sinon, il$var2
s'agirait d'un modèle à comparer$var1
.Une chose que vous ne pouvez pas faire
[[ … ]]
est d’utiliser une variable en tant qu’opérateur. Par exemple, ceci est parfaitement légal (mais rarement utile):Dans votre exemple
la commande à l' intérieur de l'
if
est[
avec les 4 arguments-d
,/home/mazimi/VirtualBox
,VMs
et]
. Le shell analyse-d /home/mazimi/VirtualBox
puis ne sait pas quoi faire avecVMs
. Vous devez empêcher le fractionnement des mots${dir}
pour obtenir une commande bien formée.En règle générale, utilisez toujours des guillemets doubles autour des substitutions de variables et de commandes, à moins que vous ne sachiez que vous souhaitez fractionner les mots et les globuler sur le résultat. Les principaux endroits où il est prudent de ne pas utiliser les guillemets sont les suivants:
foo=$bar
(mais notez que vous avez besoin des guillemets dansexport "foo=$bar"
ou dans les affectations de tableaux, par exemplearray=("$a" "$b")
);case
déclaration:case $foo in …
;=
ou==
opérateur ( à moins que vous ne voulez pattern matching):[[ $x = "$y" ]]
.Dans tous ces cas, il est correct d’utiliser des guillemets doubles. Par conséquent, vous pouvez également ignorer les règles avancées et utiliser les guillemets tout le temps.
la source
[
c’est bien du système III en 1981 , je pensais que c’était plus vieux.Implicite dans cette question est
${variable_name}
ne veut pas dire ce que vous pensez que ça fait…… Si vous pensez que cela a quelque chose à voir avec des problèmes causés par des espaces (valeurs variables). c'est bien pour ça:
${variable_name}
et rien d'autre! 1 ne font pas une bonnemoins que vous cesuit avec un personnage qui pourrait faire partie d'un nomvariable: une lettre (-ou-), un traitsoulignement (), ou un chiffre (-). Et même alors, vous pouvez contourner ce problème:
${variable_name}
A
Z
a
z
_
0
9
Je n'essaie pas de décourager son utilisation -
echo "${bar}d"
c'est probablement la meilleure solution ici - mais de décourager les gens de s'appuyer sur des accolades au lieu de citations, ou d'appliquer instinctivement les accolades et de demander ensuite: «Ai-je besoin de citations aussi? ” Vous devriez toujours utiliser des guillemets, sauf si vous avez une bonne raison de ne pas le faire, et vous êtes sûr de savoir ce que vous faites._________________
1 Sauf, bien entendu, par le fait que les formes fantaisistes de développement des paramètres , par exemple, et , se fondent sur la syntaxe. En outre, vous devez utiliser , etc. pour référencer les paramètres de position 10, 11, etc., les guillemets ne vous aideront pas.
${parameter:-[word]}
${parameter%[word]}
${parameter}
${10}
${11}
la source
Pour gérer les espaces et les caractères spéciaux vierges dans les variables, vous devez toujours les entourer de guillemets doubles. Définir un IFS approprié est également une bonne pratique.
Recommandé: http://www.dwheeler.com/essays/filenames-in-shell.html
la source