Il est grand temps de résoudre cette énigme qui me dérange depuis des années ...
Je l'ai rencontré de temps en temps et j'ai pensé que c'était la voie à suivre:
$(comm "$(arg)")
Et j'ai pensé que mon point de vue était fortement soutenu par l'expérience. Mais je n'en suis plus si sûr. Shellcheck ne peut pas non plus se décider. C'est à la fois:
"$(dirname $0)"/stop.bash
^-- SC2086: Double quote to prevent globbing and word splitting.
Et:
$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.
Quelle est la logique derrière?
(Il s'agit de la version 0.4.4 de Shellcheck, btw.)
bash
quoting
command-substitution
Tomasz
la source
la source
"$(dirname "$0")"/stop.bash
:? Cela semble fonctionner ... Quelle est l'histoire?shell_level_1 $(shell_level_2) shell_level_1
lorsque vous êtes à l'intérieur du,$(....)
vous entrez un "sous-niveau" de shell, MAIS vous pouvez l'écrire comme si vous étiez au niveau primaire (c'est-à-dire que vous pouvez directement écrire"
au lieu de\"
, etc.). ex:touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to
trouver \ "/ tmp / un fichier \" `etprint \$5
. Avec$(...)
pas besoin: les adapte shell au nouveau niveau et vous pouvez écrire directement comme si votre interprète est maintenant à ce niveau aussi.Réponses:
Vous devez utiliser
"$(somecmd "$file")"
.Sans les guillemets, un chemin avec un espace sera divisé dans l'argument to
somecmd
et ciblera le mauvais fichier. Vous avez donc besoin de citations à l'intérieur.Tous les espaces dans la sortie de
somecmd
provoqueront également le fractionnement, vous avez donc besoin de guillemets à l'extérieur de la substitution de commande entière.Les citations à l'intérieur de la substitution de commande n'ont aucun effet sur les citations à l'extérieur. Le manuel de référence de Bash n'est pas trop clair à ce sujet, mais BashGuide le mentionne explicitement . Le texte dans POSIX l' exige également, car "tout script shell valide" est autorisé à l'intérieur
$(...)
:Exemple:
une. Pas de devis,
dirname
traite les deux./space
ethere/foo
:b. Citations à l'intérieur,
dirname
processus./space here/foo
, dons./space here
, divisés en deux:c. Les citations à l'extérieur
dirname
traitent les deux./space
et leshere/foo
sorties sur des lignes distinctes, mais maintenant les deux lignes forment un seul argument :ré. Citations à l'intérieur et à l'extérieur, cela donne la bonne réponse:
(cela aurait peut-être été plus simple si
dirname
seulement traité le premier argument, mais cela ne montrerait pas la différence entre les cas a et c.)Notez qu'avec
dirname
(et éventuellement d'autres), vous devez également ajouter--
, pour éviter que le nom de fichier ne soit pris en option au cas où il commencerait par un tiret, alors utilisez"$(dirname -- "$file")"
.la source
$( )
crée un nouveau contexte, donc les guillemets à l'intérieur sont indépendants des guillemets à l'extérieur. Et vous voulez généralement des guillemets dans les deux contextes.