J'utilise GNU bash
4.3.48
. Considérez les deux commandes suivantes qui ne diffèrent que par un seul signe dollar.
Commande 1:
echo "(echo " * ")"
Commande 2:
echo "$(echo " * ")"
Leur sortie est, respectivement,
(echo test.txt ppcg.sh )
et
*
Donc, évidemment, dans le premier cas, le *
est globulé, ce qui signifie que le premier guillemet va avec le second pour former une paire, et le troisième et le quatrième forment une autre paire.
Dans le second cas, le *
n'est pas globlé, et il y a exactement deux espaces supplémentaires dans la sortie, un avant l'astérisque et un après, ce qui signifie que le deuxième guillemet va avec le troisième et le premier va avec le quatrième.
Y a-t-il d'autres cas en dehors de la $()
construction que les guillemets ne correspondent pas au suivant, mais sont imbriqués à la place? Ce comportement est-il bien documenté et si oui, où puis-je trouver le document correspondant?
Réponses:
Toutes les constructions imbriquées qui peuvent être interpolées à l'intérieur de chaînes peuvent avoir d'autres chaînes à l'intérieur: elles sont analysées comme un nouveau script, jusqu'au marqueur de fermeture, et peuvent même être imbriquées à plusieurs niveaux. Tout sauf un commence par un
$
. Tous sont documentés dans une combinaison du manuel Bash et de la spécification du langage de commande shell POSIX.Il y a quelques cas de ces constructions:
Substitution de commandes avec
$( ... )
, comme vous l'avez trouvé. POSIX spécifie ce comportement :Les citations font partie de scripts shell valides, elles sont donc autorisées avec leur signification normale.
`
également.L'élément "word" des instances de substitution de paramètres avancées telles que
${parameter:-word}
. La définition de "mot" est :- qui inclut du texte entre guillemets et même des guillemets mixtes
a"b"c'd'e
- bien que le comportement réel des extensions soit un peu plus libéral que cela, et par exemple${x:-hello world}
fonctionne aussi.Expansion arithmétique avec
$(( ... ))
, bien qu'elle soit largement inutile là-bas (mais vous pouvez également imbriquer la substitution de commandes ou les extensions de variables, puis avoir des guillemets utiles à l'intérieur). POSIX déclare que :ce comportement est donc explicitement requis. Cela signifie
echo "abc $((4 "*" 5))"
faire de l'arithmétique, plutôt que de globuler.Notez cependant que l'
$[ ... ]
expansion arithmétique à l' ancienne n'est pas traitée de la même manière: les guillemets seront une erreur s'ils apparaissent, que l'expansion soit citée ou non. Ce formulaire n'est plus du tout documenté et n'est pas destiné à être utilisé de toute façon.$"..."
, qui utilise en fait l'"
élément central.$"
est traité comme une seule unité.Il y a un autre cas d'imbrication auquel vous ne vous attendez pas, n'impliquant pas de guillemets, qui est avec l' expansion d'accolade : se
{a,b{c,d},e}
développe en "a bc bd e".${x:-a{b,c}d}
ne niche pas , cependant; il est traité comme une substitution de paramètres donnant "a{b,c
", suivi de "d}
". Cela est également documenté :En règle générale, toutes les constructions délimitées analysent leur corps indépendamment du contexte environnant (et les exceptions sont traitées comme des bogues ). En substance, en voyant
$(
le code de commande de substitution demande que l'analyseur de consommer ce qu'il peut du corps comme si elle est un nouveau programme, puis vérifie que le marqueur de terminaison prévu (une séquence d' échappement)
ou))
ou}
) apparaît une fois que les courses sous-analyseur des choses qu'il peut consommer.Si vous pensez au fonctionnement d'un analyseur à descente récursive , ce n'est qu'une simple récursivité dans le cas de base. C'est en fait plus facile à faire que dans l'autre sens, une fois que vous avez une interpolation de chaîne. Quelle que soit la technique d'analyse sous-jacente, les shells supportant ces constructions donnent le même résultat.
Vous pouvez imbriquer des citations aussi profondément que vous le souhaitez à travers ces constructions et cela fonctionnera comme prévu. Nulle part ne se confondra en voyant une citation au milieu; au lieu de cela, ce sera le début d'une nouvelle chaîne entre guillemets dans le contexte intérieur.
la source
"blah/blah\n$(cat "${tmpdir}/${filename}.jpdf")"
, pourquoi le deuxième guillemet double n'est-il pas la fin du premier guillemet double (comme le montre la coloration syntaxique dans votre réponse), mais le début d'une chaîne à l'intérieur$(...)
? Est-ce parce que l'analyseur de bash est de haut en bas, plutôt que de bas en haut?"${var-"foo"}"
(echo "${-+"*"}"
est la même queecho *
dans le shell Bourne ou Korn par exemple) et le comportement sera clairement indéterminé dans la prochaine version de la norme . Voir aussi la discussion sur mail-archive.com/[email protected]/msg00167.htmlPeut-être que regarder les deux exemples avec
printf
(au lieu deecho
) aidera:Il imprime
(echo
(le premier mot, y compris un espace de fin), certains fichiers et le mot de fermeture)
.La parenthèse n'est qu'une partie de la chaîne entre guillemets
(echo
.L'astérisque (désormais sans guillemets, car les deux guillemets doubles sont associés) est développé en tant que glob à une liste de fichiers correspondants.
Et puis, la parenthèse fermante.
Cependant, votre deuxième commande fonctionne comme suit:
Le
$
commence une substitution de commande. Cela commence une nouvelle fois la citation.L'astérisque est cité
" * "
et c'est ce que la commande (ici c'est une commande et non une chaîne entre guillemets)echo
sort. Enfin,printf
reformate le*
et l'imprime sous< * >
.la source