ChatGPT解决这个技术问题 Extra ChatGPT

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

在 Linux 上,我可以这样做:

$ FOO=BAR ./myscript

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

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

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

$ OPTION=1 ./myscript

$ ./myscript

会非常方便。

我想我的问题是为什么你需要这样做?我认为有更好的解决方案。
这通常不是一个有用的问题,@EBGreen。 UNIX shell 中存在该功能这一事实表明它是有用的。突然想到:控制 git 用于提交的用户名和电子邮件地址。这些没有命令行选项 - 您必须在每个存储库中的 ~/.gitconfig、.git/config 或 envars 中设置它们。在这些选项中,envar 显然更容易即时设置(并且可以方便地覆盖文件中的值)。因此,如果我想在 powershell 中为一个“git commit”更改我的作者姓名,该怎么做呢?
完全同意问为什么需要这样做是没有意义的。在 Linux 的命令行中执行时,它与罗宋汤一样常见,而我们这些现在被迫遭受 powershell 的人(如果曾经存在的话,这是一个语法噩梦)不断地不得不寻找明显技术的答案。大多数时候,它们甚至不存在于 powershell 中,除非您计算编写长脚本来做一些琐碎的事情。算我对那个壳深感沮丧......
感谢@FranklinYu 的链接,但在这一点上,它有望在 v7.0 之后不久的将来版本中出现。

K
Keith Hill

通常,通过参数而不是全局(环境)变量将信息传递给脚本会更好。但如果这是你需要做的,你可以这样做:

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

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

Remove-Item Env:\FOO

只是一个想法:你不能只产生一个新的 PowerShell 进程,通过 -Command 参数将脚本块传递给它吗?这样您就不必事后清理环境,因为这将包含在子进程中。虽然我正在与 PowerShell MVP 交谈,所以这可能不起作用:-)
Keith,我们在 Pscx 中有一个 push-environmentblock 和 pop-environmentblock 用于这种场景;-)
约翰内斯,这也行,但不知何故似乎在作弊。 :-) PSCX Push/Pop-EnvironmentBlock(我更改为以这种方式工作的那个)可以工作,但它没有脚本块所具有的自动清理支持。
您不需要将 env:foo 设置回其旧值(可能未设置)而不是删除它吗?
正如@Joey 提到的,如果你想干净地做环境变量,你可以:& {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}...有些人可能会说unwieldy,但会避免副作用...
k
kizzx2

我对这个问题有足够的动力,所以我继续为它写了一个脚本: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

A
Alexander Fadeev

2 种简单的方法在一行中完成:

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

只是从其他答案(谢谢大家)中总结了一些信息,这些答案由于某种原因不包含纯单行词。


不起作用 - 变量没有被删除。
第二个 vay 对我有用,Windows 11
使用 $env:FOO=$null 而不是 $env:FOO=''
g
golvok

通过使用脚本块调用 powershell 来创建“子shell”,您可以将更改范围限定为环境:

pwsh -Command { $env:MYVAR="myvalue"; .\path\to.exe }

P
Peter Mortensen

要完成与 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。


z
zett42

您可以通过将脚本作为 Job 运行来做到这一点:

Start-Job -InitializationScript { $env:FOO = 'BAR' } -FilePath .\myscript.ps1 |
    Receive-Job -Wait -AutoRemoveJob

您还可以使用 Start-JobArgumentList 参数将参数传递给脚本:

$jobArgs = @{
    InitializationScript = { $env:FOO = 'BAR' } 
    FilePath             = '.\myscript.ps1'
    ArgumentList         = 'arg1', 'arg2' 
}
Start-Job @jobArgs | Receive-Job -Wait -AutoRemoveJob

的优点和缺点

您不必在脚本完成后重置环境变量(即使存在异常,也需要 try / finally 才能正确执行)。

环境变量将是启动脚本的真正本地变量。它不会影响其他可能并行启动的作业。

该脚本将在其自己的、有些孤立的环境中运行。这意味着启动的脚本不能设置主脚本的变量,它必须使用 Write-Output 与主脚本通信。这可能是优点或缺点,具体取决于用例。


是否可以使用需要用户输入的交互式命令做类似的事情?
N
NReilingh

考虑到 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


R
Robert Walters

在我的用例中,我需要设置一个环境变量,以便可以在 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}
...

A
Andy Schneider

您可以将变量范围限定为函数和脚本。

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

如果您想要正式并使用 new-variable 声明变量,New-Variable 也有一个 -scope 参数。


嗯......不要认为这个答案适用于此。 PowerShell 变量不是环境变量。基于这个问题,提问者没有使用环境变量作为暂存空间(就像在 CMD 中那样[如果是这种情况,这个答案将适用]),但需要在调用外部命令然后恢复之前操纵环境之后的环境(或类似的东西)。