在 Linux 上,我可以这样做:
$ FOO=BAR ./myscript
在设置了环境变量 FOO 的情况下调用“myscript”。
在 PowerShell 中是否有类似的可能,即无需先设置变量、调用命令,然后再次取消设置变量?
为了更清楚地了解我的用例 - 我不想将其用作脚本的一部分。相反,我有一个第三方脚本,我可以使用环境变量控制其行为,但在这种情况下,不是命令行参数。所以能够在打字之间交替
$ OPTION=1 ./myscript
和
$ ./myscript
会非常方便。
通常,通过参数而不是全局(环境)变量将信息传递给脚本会更好。但如果这是你需要做的,你可以这样做:
$env:FOO = 'BAR'; ./myscript
环境变量 $env:FOO 可以稍后删除,如下所示:
Remove-Item Env:\FOO
我对这个问题有足够的动力,所以我继续为它写了一个脚本: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
2 种简单的方法在一行中完成:
$env:FOO='BAR'; .\myscript; $env:FOO=''
$env:FOO='BAR'; .\myscript; Remove-Item Env:\FOO
只是从其他答案(谢谢大家)中总结了一些信息,这些答案由于某种原因不包含纯单行词。
$env:FOO=$null
而不是 $env:FOO=''
通过使用脚本块调用 powershell 来创建“子shell”,您可以将更改范围限定为环境:
pwsh -Command { $env:MYVAR="myvalue"; .\path\to.exe }
要完成与 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
环境变量的命令行(包括其他参数)执行 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。
您可以通过将脚本作为 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
的优点和缺点
您不必在脚本完成后重置环境变量(即使存在异常,也需要 try / finally 才能正确执行)。
环境变量将是启动脚本的真正本地变量。它不会影响其他可能并行启动的作业。
该脚本将在其自己的、有些孤立的环境中运行。这意味着启动的脚本不能设置主脚本的变量,它必须使用 Write-Output 与主脚本通信。这可能是优点或缺点,具体取决于用例。
考虑到 CMD 是 Windows 内核上的本机 CLI(并且仍然是许多工具的自动化界面),您可能会在 CMD 提示符或接受 CMD 控制台语句的界面中使用 powershell.exe
执行您的 PowerShell 脚本。
如果您使用 -File
参数将脚本传递给 powershell.exe
,则无法使用其他 PowerShell 代码设置脚本访问的环境变量,因此您可以在调用之前在 CMD 环境中设置环境变量powershell.exe
:
> set foo=bar && powershell.exe -File .\script.ps1
单个 &
也可以工作,但如果 set
由于某种原因失败,将允许命令继续。 (这甚至可能吗?我不知道。)
此外,将 "foo=bar"
括在引号中可能更安全,这样后面的任何内容都不会作为变量内容传递给 set
。
在我的用例中,我需要设置一个环境变量,以便可以在 Docker Compose 脚本中使用它。在我的 Powershell 脚本中,我使用分号定义变量,然后在同一行调用 docker-compose
$env:PLATFORM="linux/x86_64" ; docker-compose up -d --build
在 docker compose 中,我现在可以使用我的 ${PLATFORM} 变量。
看起来像这样
...
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
platform: ${PLATFORM}
...
您可以将变量范围限定为函数和脚本。
$script:foo = "foo"
$foo
$function:functionVariable = "v"
$functionVariable
如果您想要正式并使用 new-variable 声明变量,New-Variable 也有一个 -scope 参数。
env:foo
设置回其旧值(可能未设置)而不是删除它吗?& {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}
...有些人可能会说unwieldy,但会避免副作用...