PowerShell: impostazione di una variabile di ambiente solo per un singolo comando


99

Su Linux posso fare:

$ FOO=BAR ./myscript

per chiamare "myscript" con la variabile d'ambiente FOO impostata.

È possibile qualcosa di simile in PowerShell, ovvero senza dover prima impostare la variabile, chiamare il comando e quindi annullare nuovamente la variabile?

Per essere più chiari sul mio caso d'uso, non voglio usarlo come parte di uno script. Piuttosto, ho uno script di terze parti il ​​cui comportamento posso controllare utilizzando le variabili di ambiente, ma, in questo caso, non gli argomenti della riga di comando. Quindi essere in grado di alternare la digitazione

$ OPTION=1 ./myscript

e

$ ./myscript

sarebbe solo molto utile.


Immagino che la mia domanda sarebbe perché dovresti farlo? Penso che ci sia una soluzione migliore.
EBGreen

20
Di solito non è una domanda utile, @EBGreen. Il fatto che la capacità sia presente nelle shell UNIX suggerisce che ce ne sia un uso. In cima alla mia testa: controllo del nome utente e dell'indirizzo email che git utilizza per i commit. Non esiste un'opzione della riga di comando per questi: devi impostarli in ~ / .gitconfig, .git / config in ogni repository o envars. Di queste opzioni, gli envar sono chiaramente più facili da impostare al volo (e sovrascrivono convenientemente i valori nei file). Quindi, se voglio cambiare il nome del mio autore per un "git commit" in PowerShell, come si fa?
Mark Reed

2
Completamente d'accordo sul fatto che chiedere perché è necessario è inutile. È comune come borscht quando si esegue dalla riga di comando su Linux e quelli di noi costretti ora a soffrire di powershell (un incubo sintattico se mai esistito) devono costantemente cercare risposte a tecniche ovvie. Il più delle volte, non esistono nemmeno in PowerShell a meno che non si contenga la scrittura di lunghi script per fare cose banali. Contami profondamente frustrato con quel guscio ...
Kim

2
Questa funzionalità è in discussione per PowerShell 6 .
Franklin Yu

1
Grazie per il collegamento, @FranklinYu, ma a questo punto sarebbe una versione futura, si spera, non troppo distante dopo la v7.0 .
mklement0

Risposte:


54

In generale, sarebbe meglio passare le informazioni allo script tramite un parametro piuttosto che una variabile globale (ambiente). Ma se è questo ciò che devi fare, puoi farlo in questo modo:

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

La variabile d'ambiente $ env: FOO può essere cancellata in seguito in questo modo:

Remove-Item Env:\FOO

2
Solo un pensiero: non potresti semplicemente generare un nuovo processo di PowerShell, passandoci lo scriptblock tramite il parametro -Command? In questo modo non devi ripulire l'ambiente in seguito, poiché ciò sarà contenuto nel processo figlio. Anche se sto parlando con un MVP di PowerShell, probabilmente non funziona :-)
Joey

2
Keith, abbiamo un push-environmentblock e un pop-environmentblock in Pscx esattamente per questo scenario ;-)
x0n

2
Johannes, anche quello funzionerebbe, ma in qualche modo sembra un inganno. :-) Il PSCX Push / Pop-EnvironmentBlock (quello che ho cambiato per far funzionare in questo modo) funzionerebbe ma non ha il supporto per la pulizia automatica di uno scriptblock.
Keith Hill,

1
Non è necessario env:fooripristinare il vecchio valore (forse non impostato) invece di rimuoverlo?
chwarr

1
come menzionato da @Joey, se vuoi fare env vars in modo pulito, potresti: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... alcuni potrebbero dire ingombranti , ma eviteranno effetti collaterali ...
Lucas

13

Mi sono abbastanza motivato riguardo a questo problema che sono andato avanti e ho scritto uno script per questo: with-env.ps1

Utilizzo:

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'altra parte, se installi Gow puoi usareenv.exe che potrebbe essere un po 'più robusto dello script veloce che ho scritto sopra.

Utilizzo:

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

4

Per ottenere l'equivalente della sintassi Unix, non solo devi impostare la variabile d'ambiente, ma devi reimpostarla al suo valore precedente dopo aver eseguito il comando. Ho ottenuto questo risultato per i comandi comuni che utilizzo aggiungendo funzioni simili alle seguenti al mio profilo PowerShell.

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

Quindi mycmdè un eseguibile che funziona in modo diverso a seconda del valore della variabile di ambiente app_master. Definendo cmd_special, ora posso eseguire cmd_specialdalla riga di comando (inclusi altri parametri) con l'estensioneapp_master variabile di ambiente impostata ... e viene ripristinata (o addirittura annullata) dopo l'esecuzione del comando.

Presumibilmente, potresti anche farlo ad-hoc per una singola chiamata.

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

In realtà dovrebbe essere più facile di così, ma a quanto pare questo non è un caso d'uso prontamente supportato da PowerShell. Forse una versione futura (o una funzione di terze parti) faciliterà questo caso d'uso. Sarebbe bello se PowerShell avesse un cmdlet che lo farebbe, ad esempio:

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

Forse un guru di PowerShell può suggerire come si potrebbe scrivere un tale cmdlet.


3

2 semplici modi per farlo in una sola riga:

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

Solo informazioni riassunte da altre risposte (grazie ragazzi) che non contengono semplici battute per qualche motivo.


0

Considerando che CMD è la CLI nativa nel kernel di Windows (ed è ancora l'interfaccia di automazione per molti strumenti), potresti eseguire lo script di PowerShell con powershell.exedal prompt di CMD o un'interfaccia che accetta le istruzioni della console CMD.

Se stai utilizzando il -Fileparametro per passare lo script powershell.exe, nessun altro codice PowerShell può essere utilizzato per impostare una variabile di ambiente a cui lo script accede, quindi puoi invece impostare le variabili di ambiente nell'ambiente CMD prima di chiamare powershell.exe:

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

Anche un singolo &funzionerà, ma consentirà al comando di continuare se setper qualche motivo fallisce. (È anche possibile? Non ne ho idea.)

Inoltre, potrebbe essere più sicuro racchiudere "foo=bar"tra virgolette in modo che nulla di seguito venga passato setcome contenuto della variabile.



-5

È possibile definire l'ambito delle variabili in funzioni e script.

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

New-Variable ha anche un parametro -scope se vuoi essere formale e dichiarare la tua variabile usando new-variable.


1
Hmmm ... Non credo che questa risposta si applichi qui. Le variabili di PowerShell non sono variabili di ambiente. In base alla domanda, il richiedente non utilizza le variabili di ambiente come spazio di lavoro (come si farebbe in CMD [se così fosse, questa risposta si applicherebbe]), ma deve manipolare l'ambiente prima di invocare un comando esterno e quindi ripristinare l'ambiente in seguito (o qualcosa in tal senso).
chwarr
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.