PowerShell: Festlegen einer Umgebungsvariablen nur für einen einzelnen Befehl

99

Unter Linux kann ich:

$ FOO=BAR ./myscript

um "myscript" mit der Umgebungsvariablen FOO aufzurufen.

Ist in PowerShell etwas Ähnliches möglich, dh ohne zuerst die Variable setzen, den Befehl aufrufen und die Variable dann wieder deaktivieren zu müssen?

Um meinen Anwendungsfall klarer zu machen: Ich möchte dies nicht als Teil eines Skripts verwenden. Ich habe vielmehr ein Skript eines Drittanbieters, dessen Verhalten ich mithilfe von Umgebungsvariablen steuern kann, in diesem Fall jedoch keine Befehlszeilenargumente. So können Sie zwischen dem Tippen wechseln

$ OPTION=1 ./myscript

und

$ ./myscript

wäre einfach sehr praktisch.

miracle2k
quelle
Ich denke meine Frage wäre, warum Sie dies tun müssten? Ich würde denken, dass es eine bessere Lösung gibt.
EBGreen
20
Das ist normalerweise keine hilfreiche Frage, @EBGreen. Die Tatsache, dass die Funktion in UNIX-Shells vorhanden ist, deutet darauf hin, dass sie verwendet werden kann. Auf den ersten Blick: Steuern des Benutzernamens und der E-Mail-Adresse, die git für Commits verwendet. Für diese gibt es keine Befehlszeilenoption. Sie müssen sie entweder in ~ / .gitconfig, .git / config in jedem Repository oder in envars festlegen. Von diesen Optionen sind Envars deutlich einfacher im laufenden Betrieb festzulegen (und überschreiben bequem die Werte in den Dateien). Also, wenn ich meinen Autorennamen für ein "Git Commit" in Powershell ändern möchte, wie geht das?
Mark Reed
2
Stimmen Sie voll und ganz zu, dass es sinnlos ist zu fragen, warum dies erforderlich ist. Es ist so üblich wie Borscht, wenn es unter Linux an der Kommandozeile ausgeführt wird, und diejenigen von uns, die jetzt gezwungen sind, mit Powershell zu leiden (ein syntaktischer Albtraum, falls es jemals einen gab), müssen ständig nach Antworten auf offensichtliche Techniken suchen. Meistens existieren sie nicht einmal in Powershell, es sei denn, Sie schreiben lange Skripte, um triviale Dinge zu tun. Zählen Sie mich zutiefst frustriert mit dieser Muschel ...
Kim
2
Diese Funktion wird derzeit für PowerShell 6 diskutiert .
Franklin Yu
1
Vielen Dank für den Link, @FranklinYu, aber an diesem Punkt wäre es hoffentlich eine nicht allzu weit entfernte zukünftige Version nach v7.0 .
mklement0

Antworten:

54

Im Allgemeinen ist es besser, Informationen über einen Parameter an das Skript zu übergeben, als über eine globale (Umgebungs-) Variable. Aber wenn Sie das tun müssen, können Sie es folgendermaßen tun:

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

Die Umgebungsvariable $ env: FOO kann später wie folgt gelöscht werden:

Remove-Item Env:\FOO
Keith Hill
quelle
2
Nur ein Gedanke: Könnten Sie nicht einfach einen neuen PowerShell-Prozess erzeugen und den Skriptblock über den Parameter -Command übergeben? Auf diese Weise müssen Sie die Umgebung anschließend nicht mehr bereinigen, da dies im untergeordneten Prozess enthalten ist. Obwohl ich mit einem PowerShell MVP spreche, funktioniert dies wahrscheinlich nicht :-)
Joey
2
Keith, wir haben einen Push-Environmentblock und einen Pop-Environmentblock in Pscx für genau dieses Szenario ;-)
x0n
2
Johannes, das würde auch funktionieren, aber irgendwie scheint es zu schummeln. :-) Der PSCX Push / Pop-EnvironmentBlock (der, den ich geändert habe, damit er auf diese Weise funktioniert) würde funktionieren, hat aber nicht die automatische Bereinigungsunterstützung, die ein Skriptblock hat.
Keith Hill
1
Müssen Sie nicht env:fooauf den alten Wert zurücksetzen (möglicherweise nicht festgelegt), anstatt ihn zu entfernen?
Chwarr
1
Wie @Joey erwähnte, wenn Sie env vars sauber machen möchten, könnten Sie: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... einige sagen vielleicht unhandlich , aber vermeiden Nebenwirkungen ...
Lucas
13

Ich war genug motiviert über dieses Problem, dass ich ein Skript dafür schrieb: with-env.ps1

Verwendung:

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

Auf der anderen Seite können Sie bei der Installation von Gow etwas verwenden, env.exedas möglicherweise etwas robuster ist als das oben geschriebene schnelle Skript.

Verwendung:

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
quelle
4

Um das Äquivalent der Unix-Syntax zu erreichen, müssen Sie nicht nur die Umgebungsvariable festlegen, sondern sie nach Ausführung des Befehls auf den vorherigen Wert zurücksetzen. Ich habe dies für allgemeine Befehle erreicht, die ich verwende, indem ich meinem PowerShell-Profil Funktionen hinzugefügt habe, die den folgenden ähnlich sind.

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

Dies mycmdgilt auch für einige ausführbare Dateien, die je nach Wert der Umgebungsvariablen unterschiedlich funktionieren app_master. Durch Definieren cmd_specialkann ich jetzt cmd_specialüber die Befehlszeile (einschließlich anderer Parameter) ausführen, wobei die app_masterUmgebungsvariable gesetzt ist ... und sie wird nach Ausführung des Befehls zurückgesetzt (oder sogar deaktiviert).

Vermutlich können Sie dies auch ad-hoc für einen einzelnen Aufruf tun.

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

Es sollte wirklich einfacher sein, aber anscheinend ist dies kein Anwendungsfall, der von PowerShell ohne weiteres unterstützt wird. Möglicherweise erleichtert eine zukünftige Version (oder eine Funktion eines Drittanbieters) diesen Anwendungsfall. Es wäre schön, wenn PowerShell ein Cmdlet hätte, das dies tun würde, z.

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

Vielleicht kann ein PowerShell-Guru vorschlagen, wie man ein solches Cmdlet schreibt.

Jason R. Coombs
quelle
3

2 einfache Möglichkeiten, dies in einer einzigen Zeile zu tun:

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

Nur zusammengefasste Informationen aus anderen Antworten (danke Leute), die aus irgendeinem Grund keine reinen Einzeiler enthalten.

Alexander Fadeev
quelle
0

In Anbetracht der Tatsache, dass CMD die native CLI im Windows-Kernel ist (und immer noch die Automatisierungsschnittstelle für viele Tools ist), führen Sie Ihr PowerShell-Skript möglicherweise über powershell.exedie CMD-Eingabeaufforderung oder eine Schnittstelle aus, die CMD-Konsolenanweisungen akzeptiert.

Wenn Sie den -FileParameter verwenden, an den Sie Ihr Skript übergeben, powershell.exekann kein anderer PowerShell-Code verwendet werden, um eine Umgebungsvariable für den Zugriff auf das Skript festzulegen. Stattdessen können Sie Ihre Umgebungsvariablen in der CMD-Umgebung festlegen, bevor Sie Folgendes aufrufen powershell.exe:

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

Eine einzelne Funktion &funktioniert ebenfalls, ermöglicht jedoch die Fortsetzung des Befehls, wenn der Befehl setaus irgendeinem Grund fehlgeschlagen ist. (Ist das überhaupt möglich? Ich habe keine Ahnung.)

Es kann auch sicherer sein, "foo=bar"in Anführungszeichen zu setzen, damit nichts, was folgt, setals variabler Inhalt übergeben wird.

NReilingh
quelle
-5

Sie können Variablen auf Funktionen und Skripte beschränken.

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

New-Variable hat auch einen -scope-Parameter, wenn Sie formal sein und Ihre Variable mit new-variable deklarieren möchten.

Andy Schneider
quelle
1
Hmmm ... Glaube nicht, dass diese Antwort hier gilt. PowerShell-Variablen sind keine Umgebungsvariablen. Basierend auf der Frage verwendet der Fragesteller keine Umgebungsvariablen als Arbeitsbereich (wie dies in CMD der Fall wäre [wenn dies der Fall wäre, würde diese Antwort zutreffen]), sondern muss die Umgebung manipulieren, bevor ein externer Befehl aufgerufen und anschließend wiederhergestellt wird die Umgebung danach (oder etwas in diesem Sinne).
Chwarr