Dans mon environnement Bash, j'utilise des variables contenant des espaces et j'utilise ces variables dans la substitution de commandes. Malheureusement, je ne trouve pas la réponse sur SE.
Quelle est la bonne façon de citer mes variables? Et comment dois-je le faire si ceux-ci sont imbriqués?
DIRNAME=$(dirname "$FILE")
ou est-ce que je cite en dehors de la substitution?
DIRNAME="$(dirname $FILE)"
ou les deux?
DIRNAME="$(dirname "$FILE")"
ou est-ce que j'utilise des anti-tiques?
DIRNAME=`dirname "$FILE"`
Quel est le bon moyen de le faire? Et comment puis-je facilement vérifier si les citations sont définies correctement?
bash
shell
quoting
command-substitution
Cousin cocaine
la source
la source
Réponses:
En ordre du pire au meilleur:
DIRNAME="$(dirname $FILE)"
ne fera pas ce que vous voulez si$FILE
contient des espaces ou des caractères globants\[?*
.DIRNAME=`dirname "$FILE"`
est techniquement correct, mais les backticks ne sont pas recommandés pour l'expansion des commandes en raison de la complexité supplémentaire liée à leur imbrication.DIRNAME=$(dirname "$FILE")
est correct, mais seulement parce que ceci est une cession . Si vous utilisez la substitution de commande dans un autre contexte, tel queexport DIRNAME=$(dirname "$FILE")
oudu $(dirname "$FILE")
, l'absence de guillemets causera des problèmes si le résultat de l'extension contient des espaces ou des caractères globaux.DIRNAME="$(dirname "$FILE")"
est la manière recommandée. Vous pouvez remplacerDIRNAME=
par une commande et un espace sans rien changer d'autre etdirname
recevoir la chaîne correcte.Pour améliorer encore plus:
DIRNAME="$(dirname -- "$FILE")"
fonctionne si$FILE
commence par un tiret.DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"
fonctionne même si$FILE
se termine par une nouvelle ligne, car elle$()
découpe les lignes à la fin de la sortie et génèredirname
une nouvelle ligne après le résultat. Sheeshdirname
, pourquoi faut-il être différent?Vous pouvez imbriquer des extensions de commandes autant que vous le souhaitez. Avec
$()
vous, créez toujours un nouveau contexte de citation pour pouvoir faire les choses suivantes:Vous ne pas voulez essayer cela avec des accents graves.
la source
$()
vous, créez toujours un nouveau contexte de citation", c'est donc comme en dehors des guillemets extérieurs. Il n'y a rien de plus, à ma connaissance.Vous pouvez toujours montrer les effets de la cotation de variable avec
printf
.Fractionnement des mots effectué le
var1
:var1
cité, donc pas de mots qui se séparent:Fractionnement du mot à l'
var1
intérieur$()
, équivalent àecho "hello" "world"
:Pas de mots qui se séparent
var1
, pas de problème pour ne pas citer le$()
:Le mot se fractionnant à
var1
nouveau:Citer les deux, le moyen le plus simple d’être sûr.
Problème globulaire
Ne pas citer de variable peut également conduire à une expansion globale de son contenu:
Notez que cela se produit après que la variable est développée uniquement. Il n'est pas nécessaire de citer un glob lors de l'affectation:
Utilisez
set -f
pour désactiver ce comportement:Et
set +f
pour le réactiver:la source
var1='hello * world'
pour illustrer également le problème.Ajout à la réponse acceptée:
Bien que je sois généralement d’accord avec la réponse de @ l0b0 ici, je soupçonne que le placement de coudes nus dans la liste «pire au meilleur» est au moins en partie le résultat de l’hypothèse qui
$(...)
est disponible partout. Je me rends compte que la question spécifie Bash, mais il y a de nombreuses fois où Bash se veut méchant/bin/sh
, ce qui n'est peut-être pas toujours le plein shell Bourne Again.En particulier, le simple shell Bourne ne saura pas quoi faire
$(...)
. Par conséquent, les scripts qui prétendent être compatibles avec ce dernier (par exemple, via une#!/bin/sh
ligne shebang) risquent de se comporter de manière erronée s’ils sont gérés par le "réel"/bin/sh
- c’est de Un intérêt particulier lorsque, par exemple, vous produisez des scripts d’initialisation ou des packages de pré-et post-scripts, vous pouvez en placer un dans un endroit surprenant lors de l’installation d’un système de base.Si vous envisagez de faire cela avec cette variable, l'imbrication est probablement moins un problème que l'exécution du script de manière prévisible. Quand c'est assez simple et que la portabilité est une préoccupation, même si je m'attends à ce que le script s'exécute généralement sur des systèmes où
/bin/sh
est Bash, j'ai souvent tendance à utiliser des backticks pour cette raison, avec plusieurs affectations au lieu d'imbrication.Cela dit, l’omniprésence des coques qui implémentent
$(...)
(Bash, Dash, et autres) nous laisse un bon endroit pour nous en tenir à la syntaxe plus jolie, plus facile à imbriquer, et plus récemment préférée de POSIX, dans la plupart des cas. toutes les raisons @ l0b0 mentionne.A part: cela est apparu occasionnellement sur StackOverflow, aussi -
la source