PowerShell:仅为单个命令设置环境变量


99

在Linux上,我可以执行以下操作:

$ FOO=BAR ./myscript

在设置了环境变量FOO的情况下调用“ myscript”。

在PowerShell中是否可能有类似的事情,即不必先设置变量,调用命令然后再次取消设置变量?

为了更清楚地了解我的用例-我不想将其用作脚本的一部分。相反,我有一个第三方脚本,可以使用环境变量来控制其行为,但是在这种情况下,不能使用命令行参数。所以能够在打字之间交替

$ OPTION=1 ./myscript

$ ./myscript

会非常方便。


我想我的问题是,为什么您需要这样做?我认为有更好的解决方案。
EBGreen

20
@EBGreen通常不是一个有用的问题。UNIX Shell中具有此功能的事实表明存在其用途。烦恼了:控制git用于提交的用户名和电子邮件地址。这些没有命令行选项-您必须在每个存储库中的〜/ .gitconfig,.git / config或envar中设置它们。在这些选项中,显然很容易即时设置envar(并方便地覆盖文件中的值)。因此,如果我想在Powershell中为一个“ git commit”更改作者姓名,该怎么做?
Mark Reed

2
完全同意,问为什么这样做是没有意义的。在Linux的命令行上执行时,这与borscht一样普遍,现在我们这些被迫遭受powershell困扰的人(如果曾经存在过语法梦night)必须不断寻找明显技术的答案。大多数时候,它们甚至不存在于powershell中,除非您指望编写长脚本来完成琐碎的事情。伯爵夫人对那个贝壳感到非常沮丧……


1
感谢您提供@FranklinYu链接,但目前希望在v7.0之后的不久的将来的版本中
mklement0

Answers:


54

通常,最好通过参数而不是全局(环境)变量将信息传递给脚本。但是,如果这是您需要执行的操作,则可以通过以下方式进行操作:

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

稍后可以删除环境变量$ env:FOO,如下所示:

Remove-Item Env:\FOO

2
只是想一想:您是否可以生成一个新的PowerShell进程,并通过-Command参数将脚本块交给它?这样,您之后就不必清理环境了,因为这将包含在子进程中。尽管我正在与PowerShell MVP交流,所以这可能不起作用:-)
Joey

2
基思,正是在这种情况下,我们在Pscx中有一个push-environmentblock和pop-environmentblock ;-)
x0n

2
约翰尼斯,那也行得通,但似乎有点作弊。:-) PSCX Push / Pop-EnvironmentBlock(更改为以这种方式进行工作的那个)可以工作,但是它不具有脚本块所具有的自动清理支持。
Keith Hill

1
您是否不需要将env:foo其重置为旧值(也许未设置)而不是将其删除?
chwarr '16

1
正如@Joey所提到的,如果您想干净地做env var,您可以:& {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}...有些人可能会说笨拙,但会避免副作用...
Lucas

13

我对这个问题有足够的动力,我继续写了一个脚本:with-env.ps1

用法:

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

另一方面,如果您安装了Gow,则可以使用env.exe它,它可能比我上面编写的快速脚本更强大。

用法:

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

要实现与Unix语法等效的功能,不仅必须设置环境变量,而且还必须在执行命令后将其重置为以前的值。我已经通过在PowerShell配置文件中添加类似于以下功能的常用命令完成了此操作。

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

因此,mycmd一些经营的不同取决于环境变量的值执行app_master。通过定义cmd_special,我现在可以执行cmd_specialapp_master设置了环境变量的情况下从命令行(包括其他参数) ...,并且在执行命令后将其重置(甚至取消设置)。

大概,您也可以针对单个调用临时执行此操作。

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

它确实应该比这更容易,但是显然,这不是PowerShell易于支持的用例。也许将来的版本(或第三方功能)会简化此用例。如果PowerShell有一个可以执行此操作的cmdlet,那就太好了,例如:

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

也许PowerShell专家可以建议如何编写这样的cmdlet。


3

只需2种简单的方法即可完成:

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

只是总结了其他答案(谢谢大家)中的信息,由于某些原因,这些答案不包含纯粹的一语。


0

考虑到CMD是Windows内核上的本机CLI(并且仍然是许多工具的自动化接口),您可能正在powershell.exe通过CMD提示符或接受CMD控制台语句的接口执行PowerShell脚本。

如果使用-File参数将脚本传递给powershell.exe,则不能使用其他PowerShell代码来设置脚本要访问的环境变量,因此可以在调用之前在CMD环境中设置环境变量powershell.exe

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

单个&命令也可以使用,但是如果由于set某种原因而失败,将允许命令继续执行。(这有可能吗?我不知道。)

同样,"foo=bar"用引号引起来可能更安全,以使后面没有任何内容set作为变量内容传递给。



-5

您可以将变量的作用域限定为函数和脚本。

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

如果要形式化并使用new-variable声明变量,则New-Variable也具有-scope参数。


1
嗯...不要以为这个答案在这里适用。PowerShell变量不是环境变量。根据这个问题,询问者没有将环境变量用作暂存空间(就像CMD中的情况一样[如果是这种情况,此答案将适用]),但是需要在调用外部命令然后还原之前对环境进行操作。之后的环境(或其他影响)。
chwarr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.