J'ai lu que vous avez besoin de guillemets doubles pour développer des variables, par exemple
if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi
fonctionnera comme prévu, tandis que
if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi
dira toujours $test ok
même si $test
est nul.
mais alors pourquoi n'avons-nous pas besoin de devis echo $test
?
echo
, les espaces supplémentaires et les nouvelles lignes seront supprimés.Réponses:
Vous avez toujours besoin de guillemets autour des variables dans tous les contextes de liste , c'est-à-dire partout où la variable peut être étendue à plusieurs valeurs, sauf si vous voulez les 3 effets secondaires de laisser une variable sans guillemets.
les contextes de liste incluent des arguments à des commandes simples comme
[
ouecho
, lesfor i in <here>
affectations aux tableaux ... Il existe d'autres contextes où les variables doivent également être citées. Le mieux est de toujours citer des variables, sauf si vous avez une très bonne raison de ne pas le faire.Considérez l'absence de guillemets (dans les contextes de liste) comme l' opérateur split + glob .
Comme si
echo $test
c'étaitecho glob(split("$test"))
.Le comportement du shell est déroutant pour la plupart des gens car dans la plupart des autres langues, vous mettez des guillemets autour de chaînes fixes, comme
puts("foo")
et non autour de variables (commeputs(var)
) tandis que dans le shell, c'est l'inverse: tout est une chaîne dans le shell, donc mettre des guillemets autour de tout serait lourd, vousecho test
, vous n'en avez pas besoin"echo" "test"
. Dans le shell, les guillemets sont utilisés pour autre chose: empêcher une signification particulière de certains caractères et / ou affecter le comportement de certaines extensions.Dans
[ -n $test ]
ouecho $test
, le shell se divisera$test
(sur les blancs par défaut), puis effectuera la génération du nom de fichier (développez tous les*
modèles, '?' ... dans la liste des fichiers correspondants), puis passera cette liste d'arguments aux commandes[
ouecho
.Encore une fois, pensez-y comme
"[" "-n" glob(split("$test")) "]"
. Si$test
est vide ou ne contient que des blancs (spc, tab, nl), alors l'opérateur split + glob renverra une liste vide, donc le[ -n $test ]
sera"[" "-n" "]"
, qui est un test pour vérifier si "-n" est la chaîne vide ou non. Mais imaginez ce qui se serait passé si$test
"*" ou "= foo" ...Dans
[ -n "$test" ]
,[
est passé les quatre arguments"["
,"-n"
,""
et"]"
(sans les guillemets), ce qui est ce que nous voulons.Que ce soit
echo
ou[
ne fait aucune différence, c'est juste que celaecho
génère la même chose, qu'il ait passé un argument vide ou aucun argument du tout.Voir aussi cette réponse à une question similaire pour plus de détails sur la
[
commande et la[[...]]
construction.la source
La réponse de @ h3rrmiller est bonne pour expliquer pourquoi vous avez besoin des guillemets pour le
if
(ou plutôt,[
/test
), mais je suppose en fait que votre question est incorrecte.Essayez les commandes suivantes, et vous verrez ce que je veux dire.
Sans les guillemets, la substitution de variable entraîne l'extension de la deuxième commande:
et les multiples espaces sont réduits en un seul:
Avec les guillemets, les espaces sont préservés.
Cela se produit parce que lorsque vous citez un paramètre (si ce paramètre est passé à
echo
,test
ou une autre commande), la valeur de ce paramètre est envoyé comme une valeur à la commande. Si vous ne le citez pas, le shell fait sa magie normale de recherche d'espaces pour déterminer où chaque paramètre commence et se termine.Ceci peut également être illustré par le programme C (très très simple) suivant. Essayez ce qui suit sur la ligne de commande (vous voudrez peut-être le faire dans un répertoire vide afin de ne pas risquer d'écraser quelque chose).
et alors...
Après l'exécution
paramtest
,$?
contiendra le nombre de paramètres qui lui ont été transmis (et ce nombre sera imprimé).la source
Il s'agit de la façon dont le shell interprète la ligne avant l'exécution d'un programme.
Si la ligne est lue
echo I am $USER
, le shell la développeecho I am blrfl
etecho
n'a aucune idée si l'origine du texte est un développement littéral ou variable. De même, si une ligne se litecho I am $UNDEFINED
, le shell se développera$UNDEFINED
en rien et les arguments d'écho le serontI am
, et c'est la fin. Puisqueecho
fonctionne très bien sans arguments,echo $UNDEFINED
est complètement valide.Votre problème avec
if
n'est pas vraiment avecif
, carif
exécute simplement le programme et les arguments qui le suivent et exécute lathen
partie si le programme se termine0
(ou laelse
partie s'il y en a un et que le programme quitte non0
):Lorsque vous utilisez
if [ ... ]
pour faire une comparaison, vous n'utilisez pas de primitives intégrées au shell. Vous demandez en fait au shell d'exécuter un programme appelé[
qui est un très léger sur-ensembletest(1)
qui nécessite que son dernier argument soit]
. Les deux programmes se terminent0
si la condition de test s'est vérifiée et1
si ce n'est pas le cas.La raison pour laquelle certains tests échouent lorsqu'une variable n'est pas définie est parce
test
que ne voit pas que vous utilisez une variable. Ergo, se[ $UNDEFINED -eq 2 ]
casse car au moment où le shell en a fini, tous lestest
arguments sont-eq 2 ]
, ce qui n'est pas un test valide. Si vous le faisiez avec quelque chose de défini, tel que[ $DEFINED -ne 0 ]
, cela fonctionnerait parce que le shell le développerait en un test valide (par exemple,0 -ne 0
).Il y a une différence sémantique entre
foo $UNDEFINED bar
, qui s'étend à deux arguments (foo
etbar
) parce qu'elle a$UNDEFINED
été à la hauteur de son nom. Comparez cela avecfoo "$UNDEFINED" bar
, qui se développe en trois arguments (foo
, une chaîne vide et `bar). Les citations forcent le shell à les interpréter comme un argument, qu'il y ait quelque chose entre eux ou non.la source
Sans les guillemets, il
$test
peut s'agir de plusieurs mots, il doit donc être cité pour ne pas casser la syntaxe, car chaque commutateur à l'intérieur de la[
commande attend un argument, ce que font les guillemets ($test
transforme ce qui se développe en un seul argument)La raison pour laquelle vous n'avez pas besoin de guillemets pour développer une variable
echo
est parce qu'elle n'attend pas un argument. Il imprimera simplement ce que vous lui direz. Ainsi, même s'il$test
s'étend à 100 mots, l'écho l'imprimera toujours.Jetez un œil aux pièges de Bash
la source
echo
?echo
. Qu'est-ce qui vous fait penser le contraire?echo $test
et ça marche (ça donne la valeur de $ test)Les paramètres vides sont supprimés s'ils ne sont pas cités:
La commande appelée ne voit pas qu'il y avait un paramètre vide sur la ligne de commande du shell. Il semble que [soit défini pour renvoyer 0 pour -n sans rien suivre. Pourquoi toujours.
La citation fait également une différence pour l'écho, dans plusieurs cas:
la source
echo
, c'est la coquille. Vous verriez le même comportement avecls
. Essayez untouch '*'
peu de temps si vous vous sentez aventureux.:)