PowerShell: definindo uma variável de ambiente apenas para um único comando

99

No Linux, posso fazer:

$ FOO=BAR ./myscript

para chamar "myscript" com a variável de ambiente FOO sendo definida.

Algo semelhante é possível no PowerShell, ou seja, sem ter que primeiro definir a variável, chamar o comando e, em seguida, cancelar a definição da variável novamente?

Para ser mais claro sobre meu caso de uso - não quero usar isso como parte de um script. Em vez disso, tenho um script de terceiros cujo comportamento posso controlar usando variáveis ​​de ambiente, mas, neste caso, não argumentos de linha de comando. Portanto, ser capaz de alternar entre digitar

$ OPTION=1 ./myscript

e

$ ./myscript

seria muito útil.

miracle2k
fonte
Eu acho que minha pergunta seria por que você precisa fazer isso? Eu acho que existe uma solução melhor.
EBGreen
20
Essa geralmente não é uma pergunta útil, @EBGreen. O fato de o recurso estar presente nos shells do UNIX sugere que há um uso para ele. Em cima da minha cabeça: controlando o nome de usuário e endereço de e-mail que git usa para commits. Não há opção de linha de comando para eles - você deve configurá-los em ~ / .gitconfig, .git / config em cada repositório ou envars. Dessas opções, os envars são claramente mais fáceis de configurar na hora (e convenientemente sobrescrevem os valores nos arquivos). Então, se eu quiser mudar meu nome de autor para um "git commit" no PowerShell, como fazer isso?
Mark Reed
2
Concordo plenamente que perguntar por que isso é necessário é inútil. É tão comum quanto o borscht ao executar na linha de comando no Linux e aqueles de nós agora forçados a sofrer com o PowerShell (um pesadelo sintático, se é que algum existiu) constantemente têm que buscar respostas para técnicas óbvias. Na maioria das vezes, eles nem existem no PowerShell, a menos que você conte a escrita de scripts longos para fazer coisas triviais. Conte-me profundamente frustrado com aquela concha ...
Kim
2
Este recurso está em discussão para PowerShell 6 .
Franklin Yu
1
Obrigado pelo link, @FranklinYu, mas neste ponto seria uma versão futura não muito distante após a v7.0 .
mklement0

Respostas:

54

Geralmente, seria melhor passar informações para o script por meio de um parâmetro em vez de uma variável global (ambiente). Mas se é isso que você precisa fazer, você pode fazer desta forma:

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

A variável de ambiente $ env: FOO pode ser excluída posteriormente da seguinte forma:

Remove-Item Env:\FOO
Keith Hill
fonte
2
Apenas um pensamento: você não poderia simplesmente gerar um novo processo do PowerShell, entregando o scriptblock a ele por meio do parâmetro -Command? Dessa forma, você não precisa limpar o ambiente posteriormente, pois isso estará contido no processo filho. Embora eu esteja falando com um MVP do PowerShell, então isso provavelmente não funciona :-)
Joey
2
Keith, temos um bloco de ambiente push e um bloco de ambiente pop no Pscx para exatamente este cenário ;-)
x0n
2
Johannes, também funcionaria, mas de alguma forma parece trapaça. :-) O PSCX Push / Pop-EnvironmentBlock (o que mudei para fazer funcionar dessa forma) funcionaria, mas não tem o suporte de limpeza automática que um scriptblock tem.
Keith Hill
1
Você não precisa env:foovoltar ao valor antigo (talvez não definido ) em vez de removê-lo?
chwarr
1
como @Joey mencionou, se você quiser fazer env vars de forma limpa, você pode: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... alguns podem dizer pesado , mas evitará efeitos colaterais ...
Lucas
13

Fiquei motivado o suficiente sobre este problema que fui em frente e escrevi um script para ele: 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 outro lado, se você instalar o Gow, poderá usar o env.exeque pode ser um pouco mais robusto do que o script rápido que escrevi acima.

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

Para realizar o equivalente da sintaxe Unix, você não só precisa definir a variável de ambiente, mas também redefini-la para seu valor anterior após executar o comando. Eu fiz isso para comandos comuns que uso adicionando funções semelhantes às seguintes ao meu perfil do PowerShell.

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

O mesmo mycmdocorre com alguns executáveis ​​que operam de maneira diferente dependendo do valor da variável de ambiente app_master. Ao definir cmd_special, agora posso executar a cmd_specialpartir da linha de comando (incluindo outros parâmetros) com a app_mastervariável de ambiente definida ... e ela é redefinida (ou mesmo removida) após a execução do comando.

Presumivelmente, você também pode fazer isso ad-hoc para uma única invocação.

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

Realmente deveria ser mais fácil do que isso, mas aparentemente este não é um caso de uso que seja prontamente compatível com o PowerShell. Talvez uma versão futura (ou função de terceiros) facilite esse caso de uso. Seria bom se o PowerShell tivesse um cmdlet que faria isso, por exemplo:

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

Talvez um guru do PowerShell possa sugerir como escrever esse cmdlet.

Jason R. Coombs
fonte
3

Duas maneiras fáceis de fazer em uma única linha:

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

Apenas informações resumidas de outras respostas (obrigado pessoal) que não contêm frases curtas puras por algum motivo.

Alexander Fadeev
fonte
0

Considerando que o CMD é a CLI nativa no kernel do Windows (e ainda é a interface de automação para muitas ferramentas), você pode estar executando o script do PowerShell com powershell.exeo prompt do CMD ou uma interface que aceita instruções do console do CMD.

Se você estiver usando o -Fileparâmetro para passar seu script powershell.exe, nenhum outro código do PowerShell pode ser usado para definir uma variável de ambiente para o script acessar, então, em vez disso, você pode definir suas variáveis ​​de ambiente no ambiente CMD antes de chamar powershell.exe:

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

Um único &também funcionará, mas permitirá que o comando continue se houver setfalha por algum motivo. (Isso é mesmo possível? Não tenho ideia.)

Além disso, pode ser mais seguro colocar "foo=bar"aspas para que nada que se segue seja passado setcomo conteúdo da variável.

NReilingh
fonte
-5

Você pode definir o escopo de variáveis ​​para funções e scripts.

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

New-Variable também tem um parâmetro -scope se você quiser ser formal e declarar sua variável usando new-variable.

Andy Schneider
fonte
1
Hmmm ... Não pense que esta resposta se aplica aqui. As variáveis ​​do PowerShell não são variáveis ​​de ambiente. Com base na pergunta, o solicitante não está usando variáveis ​​de ambiente como espaço de rascunho (como faria no CMD [se fosse esse o caso, esta resposta se aplicaria]), mas precisa manipular o ambiente antes de invocar um comando externo e, em seguida, restaurar o ambiente depois (ou algo nesse sentido).
chwarr