Pourquoi l'expansion de variable bash conserve-t-elle des guillemets?

12
> echo "hi"
hi
> VAR='echo "hi"'
> $VAR
"hi"

Pourquoi la sortie des commandes ci-dessus est-elle différente?

Une chose similaire se produit avec des guillemets simples:

> VAR="echo 'hi'"
> $VAR
> 'hi'
Cory Klein
la source
6
Veuillez ne pas prendre l'habitude d'incorporer des extraits de script exécutables dans des variables. Au mieux, cela a tendance à être délicat et evalest un champ de mines de failles de sécurité potentielles que vous devez
surveiller
@ jw013 Bon point et excellents articles. J'aime la citation "Les variables contiennent des données, les fonctions contiennent du code." à partir du premier lien, mais pour mon usage, les données qui sont données à une fonction (dans ce cas, at) sont du code. Des conseils sur une manière plus sûre d'organiser / collecter le code qui sera donné à at?
Cory Klein
atprend la shsyntaxe en entrée. Générer des entrées pour atgénérer des shsyntaxes valides et correctement citées à partir d'entrées arbitraires, ce qui n'est pas anodin, j'essaierais donc de l'éviter si possible. Il serait vraiment utile que vous puissiez donner un peu plus de détails sur ce que vous essayez d'accomplir.
jw013
Désolé, je ne voulais pas vous distraire avec trop de détails, mais ce que je fais n'est pas vraiment compliqué, OMI. Je crée un script qui prend un "temps" et un "message". Il s'exécute ensuite atpendant le «temps» donné et indique atd'exécuter la commande dzen2. dzen2prend le "message" de stdin et utilise également d'autres paramètres statiques. La difficulté est que j'ai besoin de dzen2diriger le paramètre "message" de l'utilisateur dans la commande, mais je ne m'exécute pas dzen2moi-même, je dis atde le faire.
Cory Klein
1
superuser.com/questions/360966/… || stackoverflow.com/questions/7454526/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Réponses:

16

La paire de devis supplémentaire ne serait consommée que par une étape d'évaluation supplémentaire. Par exemple forcé par eval:

bash-4.2$ VAR='echo "hi"'

bash-4.2$ $VAR
"hi"

bash-4.2$ eval $VAR
hi

Mais c'est généralement une mauvaise idée de mettre des commandes avec des paramètres dans une chaîne. Utilisez plutôt un tableau:

bash-4.2$ VAR=(echo "hi")

bash-4.2$ "${VAR[@]}"
hi
homme au travail
la source
1
Il est également important de noter que les devis sont évalués différemment; les guillemets doubles (") permettent d'évaluer la chaîne incluse, les guillemets simples (') affichent la chaîne sous forme littérale. Exemple: "$(ls)"et '$(ls)'. C'est la raison pour laquelle les guillemets apparaissent dans les exemples de questions originales.
Joseph Kern
Un tableau est également une source de problèmes. Le code appartient aux fonctions, les données aux variables. L'exemple que vous présentez ne fonctionne que parce que les guillemets sont supprimés dans la division du tableau. Un printf '<%s> ' "${VAR[@]}"indique que les devis ont déjà été supprimés. Si vous définissez VAR comme VAR=(echo \"hi\")ayant réellement des guillemets, le même problème réapparaît, $ ${VAR[@]}sera imprimé"hi"
9

La suppression des devis ne se produit que sur les mots d'entrée d'origine, pas sur le résultat des extensions. Les citations qui font partie de variables étendues ne sont pas modifiées.

jw013
la source
2

Si vous reculez un peu, vous pouvez voir pourquoi la substitution de variables doit absolument conserver les guillemets.

Le point de guillemets dans un shell Unix / Linux / BSD est de garder ensemble des morceaux d'une chaîne qui autrement seraient analysés en plusieurs chaînes. Étant donné que par défaut, un shell utilise des espaces comme séparateur de jetons, une chaîne avec des espaces (comme "un deux trois"), si elle n'est pas citée ou échappée d'une manière ou d'une autre, serait analysée en 3 chaînes: "un", "deux" et "trois".

Si un programmeur veut une chaîne avec la valeur d'une variable interpolée:

VAR=two
STRING="one $VAR three"

le shell ne doit absolument pas supprimer les guillemets: la chaîne contenant des espaces serait analysée comme 3 chaînes plus petites.

Bruce Ediger
la source