Annuler la définition d'une variable d'environnement pour une commande

24

Je peux exécuter ENV_VAR=value commandpour exécuter commandavec une valeur spécifique pour ENV_VAR. Quel est l'équivalent de désinitialiser ENV_VARpour command?

Alexey Romanov
la source
7
À part: commandest un choix malheureux d'espaces réservés, car il existe en fait une commande intégrée de ce nom. mycommandou somecommandou tel pourrait être une meilleure habitude pour entrer.
Charles Duffy
@CharlesDuffy, j'utilise habituellement cmdpour ça.
Stéphane Chazelas

Réponses:

35

À part l' -ioption, qui efface tout l'environnement, POSIX envne fournit aucun moyen de supprimer une variable.

Cependant, avec quelques envimplémentations (y compris GNU, busybox'et FreeBSD au moins), vous pouvez faire:

env -u ENV_VAR command

Ce qui fonctionnerait pour supprimer chaque instance d'une ENV_VARvariable de l'environnement (notez cependant que cela ne fonctionne pas pour la variable d'environnement avec un nom vide ( env -u ''soit donne une erreur ou est inefficace selon l'implémentation même si tous acceptent env '=value', probablement une limitation) encourus par la unsetenv()fonction C dont POSIX a besoin pour retourner une erreur pour la chaîne vide, alors qu'il n'y a pas de limitation pour putenv())).

Portablement (dans les shells POSIX), vous pouvez faire:

(unset -v ENV_VAR; exec command)

(notez qu'avec certains shells, l'utilisation execpeut changer ce qui commandest exécuté: exécute celle du système de fichiers au lieu d'une fonction ou d'une fonction intégrée par exemple (et contournerait aliasévidemment l'expansion), comme envci-dessus. Vous voudriez l'omettre dans ces cas) .

Mais cela ne fonctionnera pas pour les variables d'environnement qui ont un nom qui n'est pas mappable à une variable de shell (notez que certains shells comme supprimeraient mkshces variables de l'environnement au démarrage de toute façon), ou les variables qui ont été marquées en lecture seule.

-vest pour le shell Bourne et bashdont le unsetsans -vpourrait annuler une ENV_VAR fonction s'il n'y avait pas de variable de ce nom. La plupart des autres shells ne désactive pas les fonctions sauf si vous passez l' -foption. (peu susceptible de faire une différence dans la pratique).

(Méfiez-vous également du bogue / anomalie de bash/ mksh/ yashdont unset, dans certaines circonstances, ne peut pas désactiver la variable, mais révéler la variable dans une portée externe )

Si perlest disponible, vous pouvez faire:

perl -e 'delete $ENV{shift@ARGV}; exec @ARGV or die$!' ENV_VAR command

Ce qui fonctionnera même pour la variable d'environnement avec un nom vide.

Maintenant, tout cela ne fonctionnera pas si vous voulez changer une variable d'environnement pour une fonction intégrée ou une fonction et que vous ne voulez pas qu'elles s'exécutent dans un sous-shell, comme dans bash:

env -u LANG printf -v var %.3f 1.2 # would run /usr/bin/printf instead
(unset -v LANG; printf -v var %.3f 1.2) # changes to $var lost afterwards

(Ici, la définition de LANG comme une approche erronée pour s'assurer .est utilisée et comprise comme le séparateur décimal. Il serait préférable d'utiliser LC_ALL=C printf...pour cela)

Avec certains shells, vous pouvez à la place créer une portée locale pour la variable à l'aide d'une fonction:

without() {
  local "$1" # $1 variable declared as initially unset in bash¹
  shift
  "$@"
}
without LANG printf -v var %.3f 1.2

Avec zsh, vous pouvez également utiliser une fonction anonyme:

(){local ENV_VAR; command}

Cette approche ne fonctionnera pas dans certains shells (comme ceux basés sur le shell Almquist), dont localne déclarent pas la variable comme initialement non définie (mais héritent de la valeur et des attributs). Dans ceux-ci, vous pouvez le faire local ENV_VAR; unset ENV_VAR, mais ne le faites pas dans mkshou yash( typesetau lieu de localpour celui-ci) car cela ne fonctionnerait pas, le unsetne ferait qu'annuler le local.

¹ Gardez également à l'esprit qu'en bashlocal, le local ENV_VAR(même s'il n'est pas défini) conserverait l' attribut d' exportation . Donc, si commandétait une fonction qui affecte une valeur à ENV_VAR, la variable serait disponible dans l'environnement des commandes appelées par la suite. unset ENV_VAReffacerait cet attribut. Ou vous pouvez utiliser local +x ENV_VARce qui garantirait également une table rase (sauf si cette variable a été déclarée en lecture seule, mais il n'y a rien que vous puissiez faire à ce sujet bash).

Stéphane Chazelas
la source
1
C'est une question distincte, mais qu'est-ce qu'une variable d'environnement avec un nom vide et comment l'utiliseriez-vous - même pour une sorte d'exploit? N'auriez-vous pas à écrire un programme qui lit l'environnement et recherche spécifiquement quelque chose comme ça?
Joe
@Joe, essayez par exemple env '=foo' python -c 'import os; print os.environ[""]'. Je ne pense pas que beaucoup de gens voudraient définir une variable comme ça.
Stéphane Chazelas
9

Il n'y a pas d'équivalent direct pour autant que je sache; vous pouvez utiliser un sous-shell:

(unset ENV_VAR; exec command)
Stephen Kitt
la source
(unset ENV_VAR; exec somecommand)si vous voulez être équivalent à l'original en efficacité (en consommant le sous-shell). En l'état, cela ajoute une fourchette supplémentaire.
Charles Duffy
1
@Charles en effet, bien que certains shells le fassent automatiquement puisque commandc'est la dernière commande de l'invocation du sous-shell.
Stephen Kitt
+1 car cette méthode est simple à saisir pour une utilisation interactive. J'utilise des sous-coques pour des modifications ponctuelles à l'environnement de la coque pour une ligne unique au lieu de me souvenir que c'est le cas env -u.
Peter Cordes
0

Vous pouvez utiliser ENV_VAR= command

Cela ne désactive pas réellement la variable, mais cela peut être utile dans de nombreux cas (les scripts shell utilisent généralement juste test -npour vérifier si une variable est définie):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
GnP
la source