PowerShell: définition d'une variable d'environnement pour une seule commande uniquement

99

Sous Linux, je peux faire:

$ FOO=BAR ./myscript

pour appeler "myscript" avec la variable d'environnement FOO en cours de définition.

Quelque chose de similaire est-il possible dans PowerShell, c'est-à-dire sans avoir à définir d'abord la variable, à appeler la commande, puis à désactiver à nouveau la variable?

Pour être plus clair sur mon cas d'utilisation, je ne veux pas l'utiliser dans le cadre d'un script. Au contraire, j'ai un script tiers dont je peux contrôler le comportement à l'aide de variables d'environnement, mais, dans ce cas, pas d'arguments de ligne de commande. Donc pouvoir alterner entre la saisie

$ OPTION=1 ./myscript

et

$ ./myscript

serait juste très pratique.

miracle2k
la source
Je suppose que ma question serait de savoir pourquoi vous auriez besoin de faire cela? Je pense qu'il existe une meilleure solution.
EBGreen le
20
Ce n'est généralement pas une question utile, @EBGreen. Le fait que la capacité existe dans les shells UNIX suggère qu'il y a une utilité. De mémoire: contrôler le nom d'utilisateur et l'adresse e-mail que git utilise pour les commits Il n'y a pas d'option de ligne de commande pour ceux-ci - vous devez les définir dans ~ / .gitconfig, .git / config dans chaque référentiel ou dans envars. Parmi ces options, les envars sont clairement plus faciles à définir à la volée (et remplacent commodément les valeurs dans les fichiers). Donc, si je veux changer le nom de mon auteur pour un "git commit" dans PowerShell, comment faire?
Mark Reed
2
Tout à fait d'accord qu'il est inutile de demander pourquoi cela est nécessaire. C'est aussi courant que le bortsch lors de l'exécution en ligne de commande sous Linux et ceux d'entre nous qui sont maintenant contraints de souffrir avec PowerShell (un cauchemar syntaxique s'il en existait un) doivent constamment chercher des réponses à des techniques évidentes. La plupart du temps, ils n'existent même pas dans PowerShell, sauf si vous comptez écrire de longs scripts pour faire des choses triviales. Comptez-moi profondément frustré par cette coquille ...
Kim
2
Cette fonctionnalité est en cours de discussion pour PowerShell 6 .
Franklin Yu
1
Merci pour le lien, @FranklinYu, mais à ce stade, ce serait une version future pas trop lointaine après la v7.0 .
mklement0

Réponses:

55

Généralement, il serait préférable de transmettre des informations au script via un paramètre plutôt qu'une variable globale (d'environnement). Mais si c'est ce que vous devez faire, vous pouvez le faire de cette façon:

$env:FOO = 'BAR'; ./myscript

La variable d'environnement $ env: FOO peut être supprimée plus tard comme ceci:

Remove-Item Env:\FOO
Keith Hill
la source
2
Juste une pensée: ne pourriez-vous pas simplement générer un nouveau processus PowerShell, en lui transmettant le scriptblock via le paramètre -Command? De cette façon, vous n'avez pas à nettoyer l'environnement par la suite, car cela sera contenu dans le processus enfant. Bien que je parle à un MVP PowerShell, cela ne fonctionne probablement pas :-)
Joey
2
Keith, nous avons un bloc d'environnement push et un bloc d'environnement pop dans Pscx pour exactement ce scénario ;-)
x0n
2
Johannes, cela fonctionnerait aussi mais semble en quelque sorte tricher. :-) Le PSCX Push / Pop-EnvironmentBlock (celui que j'ai changé pour fonctionner de cette façon) fonctionnerait mais il n'a pas le support de nettoyage automatique d'un scriptblock.
Keith Hill le
1
N'avez-vous pas besoin de env:foorevenir à son ancienne valeur (peut-être non définie) au lieu de la supprimer?
chwarr
1
comme @Joey l'a mentionné, si vous voulez faire des variables d'environnement proprement, vous pouvez: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... certains diront peut-être difficile à manier , mais éviteront les effets secondaires ...
Lucas
13

J'ai été suffisamment motivé par ce problème pour que je me lance dans l' écriture d'un script: with-env.ps1

Usage:

with-env.ps1 FOO=foo BAR=bar your command here

# Supports dot-env files as well
with-env.ps1 .\.env OTHER_ENV=env command here

D'un autre côté, si vous installez Gow, vous pouvez utiliser env.exece qui pourrait être un peu plus robuste que le script rapide que j'ai écrit ci-dessus.

Usage:

env.exe FOO=foo BAR=bar your command here

# To use it with dot-env files
env.exe $(cat .env | grep.exe -v '^#') SOME_OTHER_ENV=val your command
kizzx2
la source
5

2 façons simples de le faire en une seule ligne:

$env:FOO='BAR'; .\myscript; $env:FOO=''
$env:FOO='BAR'; .\myscript; Remove-Item Env:\FOO

Juste des informations résumées à partir d'autres réponses (merci à vous) qui ne contiennent pas de pure one-liners pour une raison quelconque.

Alexandre Fadeev
la source
4

Pour accomplir l'équivalent de la syntaxe Unix, vous devez non seulement définir la variable d'environnement, mais vous devez la réinitialiser à sa valeur antérieure après avoir exécuté la commande. J'ai accompli cela pour les commandes courantes que j'utilise en ajoutant des fonctions similaires aux suivantes à mon profil PowerShell.

function cmd_special()
{
  $orig_master = $env:app_master
  $env:app_master = 'http://host.example.com'
  mycmd $args
  $env:app_master = $orig_master
}

Il en mycmdva de même pour certains exécutables qui fonctionnent différemment selon la valeur de la variable d'environnement app_master. En définissant cmd_special, je peux maintenant exécuter à cmd_specialpartir de la ligne de commande (y compris d'autres paramètres) avec la app_mastervariable d'environnement définie ... et elle est réinitialisée (ou même non définie) après l'exécution de la commande.

Vraisemblablement, vous pouvez également effectuer cette opération ad hoc pour une seule invocation.

& { $orig_master = $env:appmaster; $env:app_master = 'http://host.example.com'; mycmd $args; $env:app_master = $orig_master }

Cela devrait vraiment être plus facile que cela, mais apparemment, ce n'est pas un cas d'utilisation facilement pris en charge par PowerShell. Peut-être qu'une version future (ou une fonction tierce) facilitera ce cas d'utilisation. Ce serait bien si PowerShell avait une applet de commande qui ferait cela, par exemple:

with-env app_master='http://host.example.com' mycmd

Peut-être qu'un gourou PowerShell peut suggérer comment écrire une telle applet de commande.

Jason R. Coombs
la source
0

Étant donné que CMD est l'interface de ligne de commande native sur le noyau Windows (et est toujours l'interface d'automatisation pour de nombreux outils), vous exécutez peut-être votre script PowerShell à powershell.exepartir de l'invite CMD ou d'une interface qui accepte les instructions de la console CMD.

Si vous utilisez le -Fileparamètre pour transmettre votre script powershell.exe, aucun autre code PowerShell ne peut être utilisé pour définir une variable d'environnement à laquelle le script doit accéder.Vous pouvez donc définir vos variables d'environnement dans l'environnement CMD avant d'appeler powershell.exe:

> set foo=bar && powershell.exe -File .\script.ps1

Un seul &fonctionnera également, mais permettra à la commande de continuer si elle a setéchoué pour une raison quelconque. (Est-ce même possible? Je n'en ai aucune idée.)

En outre, il peut être plus sûr de placer des "foo=bar"guillemets afin que rien de ce qui suit ne soit transmis setcomme contenu de la variable.

NReilingh
la source
-5

Vous pouvez étendre des variables à des fonctions et des scripts.

$script:foo = "foo"
$foo
$function:functionVariable = "v"
$functionVariable

New-Variable a également un paramètre -scope si vous voulez être formel et déclarer votre variable en utilisant new-variable.

Andy Schneider
la source
1
Hmmm ... Ne pensez pas que cette réponse s'applique ici. Les variables PowerShell ne sont pas des variables d'environnement. Sur la base de la question, le demandeur n'utilise pas les variables d'environnement comme espace de travail (comme on le ferait dans CMD [si tel était le cas, cette réponse s'appliquerait]), mais doit manipuler l'environnement avant d'appeler une commande externe, puis restaurer l'environnement par la suite (ou quelque chose à cet effet).
chwarr