web-dev-qa-db-fra.com

Exporter une variable contenant un point (.)

Comment exporter une variable qui contient un point. J'obtiens 'nom de variable invalide' quand j'ai essayé:

 export my.home=/tmp/someDir
-ksh: my.home=/tmp/someDir: invalid variable name

Même le point métacaractère qui s'échappe (.) N'a pas aidé non plus

$ export my\.home=/tmp/someDir
export: my.home=/tmp/someDir: is not an identifier
41
user1587504

Au moins pour bash la page de manuel définit la syntaxe d'exportation comme suit:

export [-fn] [name[=Word]] ...

Il définit également un "nom" comme:

   name   A  Word  consisting  only  of alphanumeric characters and under‐
          scores, and beginning with an alphabetic character or an  under‐
          score.  Also referred to as an identifier.

Par conséquent, vous ne pouvez vraiment pas définir une variable comme my.home car il ne s'agit pas d'un identifiant valide.

Je suis très sûr que votre ksh a une définition très similaire d'un identifiant et ne permet donc pas ce type de variables aussi. (Jetez un œil à sa page de manuel.)

Je suis également très sûr qu'il existe une sorte de norme générale (POSIX?) Spécifiant ce qui est autorisé comme identifiant (et donc comme nom de variable).


Si vous avez vraiment besoin de ce type de variable pour une raison quelconque, vous pouvez utiliser quelque chose comme

env "my.home=/tmp/someDir" bash

pour le définir quand même. Mais là encore, vous ne pourrez pas y accéder en utilisant la syntaxe Shell normale. Dans ce cas, vous aurez probablement besoin d'une autre langue comme Perl:

Perl -e 'print $ENV{"my.home"}'

Par exemple

env "my.home=/tmp/someDir" Perl -le 'print $ENV{"my.home"}'

devrait imprimer votre chemin.

54
michas

Alors que les variables d'environnement peuvent avoir n'importe quel nom (y compris la chaîne vide) ne contenant pas de signe égal ou d'octet nul, les shells mappent les variables d'environnement aux variables Shell et dans la plupart des shells, les noms de variables sont limités à ASCII caractères alphanumériques et _ où le premier caractère ne peut pas être un chiffre (sauf pour les paramètres de position et autres paramètres spéciaux comme $*, $-, $@,…, (Qui ne sont pas mappés aux variables d'environnement correspondantes)). Notez également que certaines variables sont réservées/spéciales par/vers le shell.

Exceptions à cela:

  • Le shell rc et ses dérivés comme es et akanga prennent en charge n'importe quel nom sauf la chaîne vide et ceux qui sont entièrement numériques ou contiennent = caractères (et exportez toujours toutes leurs variables vers l'environnement, et méfiez-vous des variables spéciales comme *, status, pid...):

    ; '%$£"' = test
    ; echo $'%$£"'
    test
    ; '' = x
    zero-length variable name
    ;
    

    Cependant, il utilise son propre encodage pour les variables dont le nom ne contient pas d'alnums ou pour les tableaux lorsqu'ils sont passés dans l'environnement des commandes en cours d'exécution:

    $ rc -c '+ = zzz; __ = zzz; a = (zzz xxx); env' | sed -n /zzz/l
    __2b=zzz$
    __5f_=zzz$
    a=zzz\001xxx$
    $ env +=x rc -c "echo $'+'"
    x
    $ env __2b=x rc -c "echo $'+'"
    x
    
  • AT&T ksh, yash et zsh (également bash mais uniquement pour les caractères à un octet) prennent en charge les alnums dans les paramètres régionaux actuels, pas seulement ASCII unités.

    $ Stéphane=1
    $ echo "$Stéphane"
    1
    

    Dans ces shells, vous pouvez changer les paramètres régionaux pour considérer la plupart des caractères comme alpha, mais cela ne fonctionnerait toujours pas pour ASCII caractères comme .. Vous pouvez duper zsh ou ksh en pensant £ est une lettre, mais pas que . ou tout autre ASCII caractère (en ce qui concerne l'autorisation des caractères dans les noms de variable, pas pour le [[:alpha:]] glob par exemple).

  • ksh93 a des variables spéciales dont le nom contient un point comme ${.sh.version}, mais ceux-ci ne sont pas mappés aux variables d'environnement et sont spéciaux. Le . est pour s'assurer qu'il n'entre pas en conflit avec d'autres variables. S'il avait choisi de l'appeler $sh_version, alors il pourrait y avoir des scripts potentiellement cassés qui utilisaient déjà cette variable (voir par exemple comment zsh a des problèmes avec son $path ou $commands tableau spécial/variables de hachage (à la csh) qui cassent certains scripts).

Notez qu'en plus des shells ne supportant pas ces variables, certains shells comme pdksh/mksh les les suppriment de l'environnement qu'ils reçoivent (bash supprime celui dont le nom est vide, ash, ksh et bash supprime les chaînes d'environnement qui ne contiennent pas de = personnage):

$ env %%%=test 1=%%% a.b=%%% mksh -c env | grep %%%
$ env %%%=test 1=%%% a.b=%%% bash -c env | grep %%%
%%%=test
a.b=%%%
1=%%%

$ Perl -le '$ENV{""}="%%%"; exec "bash", "-c", "env"' | grep %%%
$ Perl -le '$ENV{""}="%%%"; exec "zsh", "-c", "env"' | grep %%%
=%%%

$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
    execve("/bin/ash",a,e);}'|tcc -run - | grep %%%
$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
    execve("/bin/zsh",a,e);}'|tcc -run - | grep %%%
%%%

Pour résumer, le mieux est de s'en tenir aux noms de variables pris en charge par la plupart des shells et même d'essayer d'utiliser les majuscules pour les variables d'environnement (et les minuscules ou les majuscules pour les variables Shell non exportées) en évitant celles qui sont spéciales dans les shells (comme IFS, PS1, BASH_VERSION...).

Si vous avez besoin de définir une telle variable dans un shell qui ne les prend pas en charge, mais ne les supprime pas, vous pouvez soit vous réexécuter, avec quelque chose comme:

#! /bin/ksh -
Perl -e 'exit 1 unless defined($ENV{"a.b"})' || exec env a.b=%%% "$0" "$@"

(évidemment, si vous avez besoin de le faire au milieu du script, cela n'aidera pas, mais vous pourriez alors jeter un œil à cette approche pour enregistrer et restaurer l'environnement d'exécution du Shell sur un re -exec). Ou essayez l'approche du débogueur:

gdb --batch-silent -ex 'call putenv("a.b=%%%")' --pid="$$"

(celui-ci semble fonctionner avec zsh, yash, csh et tcsh sur Linux AMD64, mais pas avec les autres shells que j'ai essayés (mksh, ksh93, bash, dash)).

9

Comme le soulignent les autres articles, les shells les plus courants ne permettent pas de définir des variables d'environnement avec des points dans le nom. Cependant, j'ai trouvé des situations, impliquant notamment Docker et des programmes invoqués, où le logiciel exigeait des valeurs clés avec des points.

Cependant, dans chacune de ces situations, ces paires clé-valeur peuvent être transmises au programme par d'autres moyens que de simples variables d'environnement. Par exemple, dans Ant, vous pouvez utiliser le "-propertyfile (nom de fichier)" pour transmettre une collection formatée de valeurs-clés au format de fichier de propriétés. Confd autorise "-backend file -file (yaml file)".

J'ai passé les variables d'environnement sous la forme "C__any_value = 'my.property.key = the value'". J'ai ensuite changé l'invocation du programme pour générer d'abord le fichier:

set | awk -- 'BEGIN { FS="'\''" } /^C__/ {print $2}' > my-key-values.txt

La commande set, dans Borne Shell, affichera chaque propriété sur une ligne distincte du formulaire

C__any_value='my.property.key=the value'

La commande awk ne traitera que les variables d'environnement commençant par C__, puis extrayez les valeurs contenues dans les guillemets simples.

Cette méthode nécessite que la valeur de la variable d'environnement soit définie sous la forme précise requise par le programme de traitement. De plus, si la valeur ou la clé de votre propriété contient des guillemets simples, vous devrez remplacer le caractère de séparation de champ awk par quelque chose que vous savez qui n'apparaîtra pas et entourer la valeur de ce caractère. Par exemple, pour utiliser % comme séparateur:

$ C__1="%my.key=the'value%"
$ set | awk -- 'BEGIN { FS="%" } /^C__/ {print $2}'
my.key=the'"'"'value

(la sortie précise dépendra de votre Shell.) Vous devrez prendre des mesures supplémentaires pour décoder l'échappement de la citation.

2
Groboclown