PowerShell: establecer una variable de entorno para un solo comando

99

En Linux, puedo hacer:

$ FOO=BAR ./myscript

para llamar a "myscript" con la variable de entorno FOO configurada.

¿Es posible algo similar en PowerShell, es decir, sin tener que configurar primero la variable, llamar al comando y luego desarmar la variable nuevamente?

Para ser más claro sobre mi caso de uso, no quiero usar esto como parte de un script. Más bien, tengo un script de terceros cuyo comportamiento puedo controlar usando variables de entorno, pero, en este caso, no argumentos de línea de comando. Entonces, poder alternar entre escribir

$ OPTION=1 ./myscript

y

$ ./myscript

sería muy útil.

miracle2k
fuente
Supongo que mi pregunta sería ¿por qué necesitarías hacer esto? Creo que hay una mejor solución.
EBGreen
20
Esa no suele ser una pregunta útil, @EBGreen. El hecho de que la capacidad esté en los shells de UNIX sugiere que tiene un uso. Fuera de mi cabeza: controlar el nombre de usuario y la dirección de correo electrónico que usa git para las confirmaciones. No hay una opción de línea de comandos para esos; debe configurarlos en ~ / .gitconfig, .git / config en cada repositorio o envars. De esas opciones, envars es claramente más fácil de configurar sobre la marcha (y anula convenientemente los valores en los archivos). Entonces, si quiero cambiar mi nombre de autor por un "git commit" en powershell, ¿cómo hacerlo?
Mark Reed
2
Totalmente de acuerdo en que preguntar por qué es necesario no tiene sentido. Es tan común como el borscht cuando se ejecuta en la línea de comandos en Linux y aquellos de nosotros ahora obligados a sufrir con powershell (una pesadilla sintáctica si alguna vez existió) tenemos que buscar constantemente respuestas a técnicas obvias. La mayoría de las veces, ni siquiera existen en PowerShell a menos que cuente escribir scripts largos para hacer cosas triviales. Cuéntame profundamente frustrado con ese caparazón ...
Kim
2
Esta característica está en discusión para PowerShell 6 .
Franklin Yu
1
Gracias por el enlace, @FranklinYu, pero en este punto sería una versión con suerte en un futuro no muy lejano después de la v7.0 .
mklement0

Respuestas:

55

Generalmente, sería mejor pasar información al script a través de un parámetro en lugar de una variable global (de entorno). Pero si eso es lo que necesita hacer, puede hacerlo de esta manera:

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

La variable de entorno $ env: FOO se puede eliminar más tarde así:

Remove-Item Env:\FOO
Keith Hill
fuente
2
Solo un pensamiento: ¿no podría simplemente generar un nuevo proceso de PowerShell, entregando el bloque de script a través del parámetro -Command? De esa manera, no tendrá que limpiar el medio ambiente después, ya que estará contenido en el proceso secundario. Aunque estoy hablando con un MVP de PowerShell, probablemente esto no funcione :-)
Joey
2
Keith, tenemos un push-environmentblock y un pop-environmentblock en Pscx exactamente para este escenario ;-)
x0n
2
Johannes, eso también funcionaría, pero de alguna manera parece una trampa. :-) El PSCX Push / Pop-EnvironmentBlock (el que cambié para que funcione de esta manera) funcionaría pero no tiene el soporte de limpieza automática que tiene un scriptblock.
Keith Hill
1
¿No necesita env:foorestablecer su valor anterior (quizás no establecido) en lugar de eliminarlo?
chwarr
1
como mencionó @Joey, si desea hacer env vars limpiamente, podría: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... algunos podrían decir que son difíciles de manejar , pero evitarán los efectos secundarios ...
Lucas
13

Me motivé lo suficiente sobre este problema que seguí adelante y escribí un script para él: with-env.ps1

Uso:

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

Por otro lado, si instala Gow , puede usar el env.exeque podría ser un poco más robusto que el script rápido que escribí anteriormente.

Uso:

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
fuente
5

2 formas sencillas de hacerlo en una sola línea:

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

Solo resumió la información de otras respuestas (gracias amigos) que no contienen frases ingeniosas por alguna razón.

Alexander Fadeev
fuente
4

Para lograr el equivalente de la sintaxis de Unix, no solo debe establecer la variable de entorno, sino que debe restablecerla a su valor anterior después de ejecutar el comando. Lo logré para los comandos comunes que uso agregando funciones similares a las siguientes a mi perfil de PowerShell.

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

También lo mycmdes algún ejecutable que opera de manera diferente dependiendo del valor de la variable de entornoapp_master . Al definir cmd_special, ahora puedo ejecutar cmd_specialdesde la línea de comando (incluidos otros parámetros) con la app_mastervariable de entorno configurada ... y se restablece (o incluso se desarma) después de la ejecución del comando.

Presumiblemente, también podría hacer esto ad-hoc para una única invocación.

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

Realmente debería ser más fácil que esto, pero aparentemente este no es un caso de uso que sea compatible con PowerShell. Quizás una versión futura (o función de terceros) facilite este caso de uso. Sería bueno si PowerShell tuviera un cmdlet que hiciera esto, por ejemplo:

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

Quizás un gurú de PowerShell pueda sugerir cómo se podría escribir tal cmdlet.

Jason R. Coombs
fuente
0

Teniendo en cuenta que CMD es la CLI nativa en el kernel de Windows (y sigue siendo la interfaz de automatización de muchas herramientas), es posible que esté ejecutando su script de PowerShell con powershell.exe desde el indicador de CMD o una interfaz que acepte declaraciones de consola CMD.

Si está utilizando el -Fileparámetro para pasar su secuencia de comandos powershell.exe, no se puede usar ningún otro código de PowerShell para establecer una variable de entorno para que acceda la secuencia de comandos, por lo que puede configurar sus variables de entorno en el entorno CMD antes de llamar powershell.exe:

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

Un solo &también funcionará, pero permitirá que el comando continúe si elset falla por alguna razón. (¿Es esto posible? No tengo ni idea).

Además, puede ser más seguro envolver "foo=bar"entre comillas para que nada de lo siguiente se pase setcomo contenido de la variable.

NReilingh
fuente
-5

Puede aplicar el alcance de las variables a funciones y scripts.

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

New-Variable también tiene un parámetro -scope si quieres ser formal y declarar tu variable usando new-variable.

Andy Schneider
fuente
1
Hmmm ... No creo que esta respuesta se aplique aquí. Las variables de PowerShell no son variables de entorno. Según la pregunta, el autor de la pregunta no está usando variables de entorno como espacio temporal (como lo haría en CMD [si ese fuera el caso, esta respuesta se aplicaría]), pero necesita manipular el entorno antes de invocar un comando externo y luego restaurar el medio ambiente después (o algo por el estilo).
chwarr