在Linux上,我可以做:
$ FOO=BAR ./myscript
在设置环境变量FOO的情况下调用myscript。
在PowerShell中是否可能出现类似的情况,即无需首先设置变量,调用命令,然后再次取消设置变量?
为了更清楚地说明我的用例——我不想把它用作脚本的一部分。相反,我有一个第三方脚本,我可以使用环境变量控制其行为,但在本例中,不能使用命令行参数。所以能够在打字之间交替
$ OPTION=1 ./myscript
and
$ ./myscript
会很方便的。
要实现与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,我现在可以使用app_master环境变量set…从命令行执行cmd_special(包括其他参数)。在执行命令后,它会被重置(甚至取消设置)。
据推测,您也可以为单个调用执行这种临时操作。
& { $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。
我对这个问题有足够的动力,因此我继续为它编写了一个脚本: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
考虑到CMD是Windows内核上的原生命令行(并且仍然是许多工具的自动化接口),您可以从CMD提示符或接受CMD控制台语句的接口中使用PowerShell .exe执行PowerShell脚本。
如果您使用-File参数将脚本传递给PowerShell .exe,则不能使用其他PowerShell代码来设置脚本访问的环境变量,因此您可以在调用PowerShell .exe之前在CMD环境中设置环境变量:
> set foo=bar && powershell.exe -File .\script.ps1
单个&也可以工作,但是如果集合由于某种原因失败,将允许命令继续执行。(这可能吗?我不知道。)
另外,用引号括起"foo=bar"可能更安全,这样就不会将后面的内容传递给set作为变量内容。
你可以通过将脚本作为Job运行来实现:
Start-Job -InitializationScript { $env:FOO = 'BAR' } -FilePath .\myscript.ps1 |
Receive-Job -Wait -AutoRemoveJob
你也可以使用Start-Job的ArgumentList参数向脚本传递参数:
$jobArgs = @{
InitializationScript = { $env:FOO = 'BAR' }
FilePath = '.\myscript.ps1'
ArgumentList = 'arg1', 'arg2'
}
Start-Job @jobArgs | Receive-Job -Wait -AutoRemoveJob
优点和缺点
You don't have to reset the environment variable after the script finishes (which would require try / finally to do it correctly even in the presence of exceptions).
The environment variable will be really local to the launched script. It won't affect other, possibly launched in parallel, jobs.
The script will run in its own, somewhat isolated environment. This means that the launched script can't set variables of the main script, it has to write to the success stream (implicitly or by calling another command that already writes to the success stream) to communicate back to the main script. This could be an advantage or a disadvantage, depending on the use case.