Le nom de la variable shell peut-il inclure un trait d'union ou un tiret (-)?

38

Je ne suis pas capable d'utiliser des -variables en shell. Est-il possible de l'utiliser, car j'ai un script qui dépend de telles variables nommées:

$export a-b=c
-bash: export: `a-b=c': not a valid identifier

$export a_b=c

Le premier lance l'erreur donnée et le second fonctionne très bien.

xyz
la source
duplication possible sur plusieurs sites de: stackoverflow.com/questions/2821043/…
Ciro Santilli a annoncé
Les coquilles ne permettent généralement pas de tels noms de variables. Vous devrez contourner le shell, peut-être même avec un programme C personnalisé chargeant les variables dans l'environnement de votre commande. Ne pouvez-vous pas résoudre ce problème (même un risque de sécurité possible)?
vonbrand le

Réponses:

47

Je n'ai jamais rencontré de shell Bourne-style permettant -un nom de variable. Seules les lettres ASCII (de chaque cas) _et les chiffres sont pris en charge, et le premier caractère ne doit pas être un chiffre.

Si vous avez un programme nécessitant une variable d'environnement ne correspondant pas aux restrictions du shell, lancez-le avec le envprogramme.

env 'strange-name=some value' myprogram

Notez que certains shells (par exemple , dash moderne , mksh, zsh) suppriment les variables dont ils n'aiment pas le nom, dans l'environnement. ( Shellshock a amené les gens à être plus prudents à propos des noms de variables d'environnement, de sorte que les restrictions vont probablement devenir plus strictes avec le temps, pas plus permissives.) Donc, si vous devez transmettre une variable dont le nom contient un caractère spécial à un programme, transmettez-la directement, sans coquille entre les deux ( env 'strange-name=some value' sh -c'…; myprogram'peut ou peut ne pas fonctionner).

Gilles, arrête de faire le mal
la source
Ne fonctionne plus.
Jesse Glick
4
@ JesseGlick Oui, c'est le cas. (Votre commentaire serait utile si vous définissiez «ne fonctionne pas»: avec quelles données? Quel est l'effet au lieu de l'effet souhaité? Et si vous dites quelle implémentation de envvous avez utilisée sur quel système d'exploitation.)
Le SO de Gilles cesse d'être le mal '
Désolé. Ubuntu Yakkety avec toutes les mises à jour, envde coreutils, à shpartir de dash: env 'with-dashes=value' bash -c 'env | fgrep dashes'fonctionne mais env 'with-dashes=value' sh -c 'env | fgrep dashes'n'imprime rien. En envsoi, c’est bien, mais Dash semble bloquer spécifiquement ces variables. Ainsi, si le programme en question est lancé via un wrapper shell avec un en- #!/bin/shtête typique , il n’existe aucun moyen apparent de transmettre de telles variables. Exemple de solution de contournement
Jesse Glick
@ JesseGlick C'est tiret supprimer la variable. Vous devez utiliser envplus près du site appelant du programme qui a besoin de ce nom de variable, sans un shell entre les deux. Dash n'est pas le seul à supprimer les variables dont il n'aime pas le nom.
Gilles 'SO- arrête d'être méchant'
1
@ JesseGlick Il est vrai que certaines choses qui fonctionnaient auparavant risquent de ne plus fonctionner: depuis shellshock , les gens sont devenus plus prudents à propos des noms de variable, et dash a en fait changé depuis que j'ai écrit cette réponse (pas comme conséquence de Shellshock, mais pour éviter un bug dans le même sens). J'ai ajouté une note à ma réponse.
Gilles 'SO- arrête d'être méchant'
15

Ce n'est pas possible dans Bash.

À partir de la section Définitions de la page de manuel de bash:

nom Un mot composé uniquement de caractères alphanumériques et de soulignés, commençant par un caractère alphabétique ou un soulignement. Aussi appelé identifiant.

Dans la section Paramètres de la page de manuel de bash:

Un paramètre est une entité qui stocke des valeurs. Il peut s'agir d'un nom, d'un numéro ou de l'un des caractères spéciaux répertoriés ci-dessous sous Paramètres spéciaux. Une variable est un paramètre désigné par un nom.

Lekensteyn
la source
2
+1 pour démontrer une nouvelle fois l'utilité des pages de
manuel
2
Ancien message que je connais, mais, je tiens à souligner que pour les nouveaux venus, les pages de manuel peuvent être assez cryptiques. Il me reste encore des moments où j'ai besoin de rechercher de meilleurs explications / exemples. N'importe qui mentirait s'ils disaient que cela ne leur est jamais arrivé.
TCZ8
1
@ TCZ8 Les seules personnes qui m'ont dit qu'ils pensaient que les pages de manuel étaient «cryptiques» sont du même genre de personnes qui ne lisent pas les messages d'erreur et se contentent de tout lire, en ignorant ce dont elles ont besoin.
Miles Rout
13

Vous pouvez accéder à une variable avec un trait d'union à l'aide d'une référence indirecte.

$ env 'my-hyphenated-variable=hello' /bin/bash
$ name='my-hyphenated-variable'
$ echo ${!name}
hello
Jon Nalley
la source
1
Je n'avais jamais entendu parler de cette fonctionnalité avant la lecture de ce commentaire. Il m'a fourni une solution bien plus simple que la réponse acceptée.
DrStrangepork
7
Ce comportement a été désactivé dans les versions les plus récentes de bash. Voir stackoverflow.com/questions/36989263/… pour une analyse approfondie de la situation.
Nicolas Dudebout
6

Si votre script dépend de la présence de traits d'union dans les noms de variables, c'est une erreur de programmation. Si cela vous convient à cause des outils que vous utilisez régulièrement pour que les noms de variables contiennent un trait d'union, vous devrez peut-être en apprendre davantage et utiliser différents outils.

Avez-vous essayé d'utiliser tr pour convertir les traits d'union en traits de soulignement?

hyphenated_name="a-b"
unhyphenated_name=$(echo $hyphenated_name | tr '-' '_')
declare -x $unhyphenated_name="some value"

Bash permet à "-" d'apparaître dans les noms de fonctions. Je fais ça tout le temps. Par exemple:

function foo-bar() {
   echo "$@"
}
Brian J. Fox
la source
2

Le caractère tiret ( -) est un caractère d'interruption et n'est pas autorisé dans les noms de variables. Il existe des moyens de pirater ceci avec des variables citées, mais son analyse est vraiment problématique. Il existe également d'autres caractères ayant des significations spéciales dans le contexte des noms de variables de bash, notamment les accolades, les parenthèses, les caractères d'opérateur et les guillemets. (par exemple {}()=+-&'"et plus)

Je suggérerais que pratiquement vous devez trouver un autre paradigme sur lequel construire votre script. Vous pourriez avoir une idée en suspens d'autres langages sur les "noms de variables variables". Ce n'est généralement pas une bonne idée dans les scripts shell.

Si vous modifiez ceci ou posez une nouvelle question avec des détails sur votre contexte et ce que vous essayez d'accomplir, nous pourrons peut-être vous proposer un bon moyen de le scripter.

Caleb
la source
2

Le manuel de Bash définit un "nom" comme:

Un «mot» composé uniquement de lettres, de chiffres et de caractères de soulignement, commençant par une lettre ou un soulignement. Les noms sont utilisés en tant que variables shell et noms de fonctions. Aussi appelé «identifiant».

Donc, vous ne pouvez pas utiliser un trait d'union dans un nom.

Michael Hoffman
la source
0

La plupart des shells ne prennent en charge que az, AZ, 0-9 et _ pour variablenames. Lire le deuxième élément de cette page .


la source
0

Vous pouvez jouer avec env et sed.

Par exemple, j'avais besoin de lire cette variable 'ELASTICSEARCH_CLUSTER-NODES'.
La commande env affiche ceci:

~ $ env
ELASTICSEARCH_CLUSTER-NODES=elasticsearch:9200
JAVA_ALPINE_VERSION=8.212.04-r0
HOSTNAME=17eb9e7fec4c
...

Donc pour extraire la variable:

ESHOST=`env | sed -n 's/ELASTICSEARCH_CLUSTER-NODES=\(.*\)/\1/p'`
Guillaume Paramelle
la source
-1

Je crois que seules les lettres, les chiffres et les traits de soulignement sont autorisés pour les variables bash. C'est le cas dans de nombreux langages de programmation (javascript étant une exception).

Je recommande de ne pas avoir votre script dépend de ces types de noms de variables.

En fait, vous devriez essayer de programmer de manière à pouvoir remplacer les noms de variables par d'autres noms et cela ne changera rien. En général, les noms de variables doivent décrire ce que contient la variable. Cela facilite beaucoup le débogage; sinon pour vous, puis pour le prochain développeur qui essaie de comprendre le code.


la source
-1

Vous pouvez utiliser la envcommande pour définir et annuler les variables d'environnement avec hiphens "-".

Pour définir vous devez utiliser env pour exécuter votre commande: env command. Vous passez les variables de cette façon:

env a-b=c command

Voyez-le travailler avec:

env a-b=c env

ou pour le rendre plus clair:

env a-b=c env|grep 'a-b'
neves
la source