PowerShell 通过脚本在环境变量范围内的灵活性

PowerShell flexibility in scope of environment variables via scripts

在 bash 中,如果我在脚本中定义一个变量(例如,set_var.sh),我可以选择这些定义是否在“运行ning”脚本后保留。 这将取决于我如何“运行”脚本,选项是:

  1. sh set_var.sh(变量不持久化)
  2. ./set_var.sh(变量不持久化,同第1点)
  3. source set_var.sh(变量持续存在)

这与 set_var.sh 中是否导出到环境的变量无关。

对于 PS 和 $env 变量,是否可以使用 PowerShell 5.1 脚本实现与上述第 1 项和第 3 项相同的内容?

有关插图,请参见下面的 (1)。


编辑:

根据 Mathias R. Jessen 的回答,上面第 3 项的等价物是“点采购”。 还有一个“中间”情况(上面没有指出,也许还有一种方法可以在 bash 中获得它),其中环境变量持续存在但 PS 变量不存在。

我的脚本:

# set_var.ps1
$env:TEST_VAR = 'test_var'
$TEST_VAR2 = 'test_var2'

我检查的内容:

> $env:TEST_VAR ; $TEST_VAR2 ;
> . .\set_var.ps1
> $env:TEST_VAR ; $TEST_VAR2 ;
test_var
test_var2
> Remove-Variable TEST_VAR2 ; Remove-Item env:TEST_VAR ;
> $env:TEST_VAR ; $TEST_VAR2 ;
> .\set_var.ps1
> $env:TEST_VAR ; $TEST_VAR2 ;
test_var
> Remove-Item env:TEST_VAR ;
> $env:TEST_VAR ; $TEST_VAR2 ;
> & .\set_var.ps1
> $env:TEST_VAR ; $TEST_VAR2 ;
test_var

(1) 持久/非持久变量示例

我有脚本 set_var.sh,内容如下:

#!/bin/bash

export TEST_VAR=test_var
TEST_VAR2=test_var2

那么下面的命令证明了我的观点:

$ echo $TEST_VAR ; echo $TEST_VAR2


$ sh set_var.sh ; echo $TEST_VAR ; echo $TEST_VAR2


$ source set_var.sh ; echo $TEST_VAR ; echo $TEST_VAR2
test_var
test_var2
$ echo $TEST_VAR ; echo $TEST_VAR2
test_var
test_var2
$ env | grep TEST_VAR
TEST_VAR=test_var
$ unset TEST_VAR ; unset TEST_VAR2
$ echo $TEST_VAR ; echo $TEST_VAR2


$ ./set_var.sh ; echo $TEST_VAR ; echo $TEST_VAR2


$ echo $TEST_VAR ; echo $TEST_VAR2


你想要 . - dot-sourcing operator - 它在调用者的范围内执行你的脚本或命令,从而在执行后保留所有变量:

# set_vars.ps1
$TEST_VAR = 123
# script.ps1
. $PSScriptRoot/set_vars.ps1
echo $TEST_VAR # outputs 123

避免 本地定义的变量在执行后持续存在,请按原样执行脚本,或显式使用 & 调用运算符:

# script.ps1
& $PSScriptRoot/set_vars.ps1
echo $TEST_VAR 
# outputs an empty string, assuming $TEST_VAR was not already defined in the callers scope

补充

关于您的编辑:

它是脚本的 直接调用/通过 & 调用 - 这与 sh / bash、运行s 进程中 - 保留环境变量更改,但不保留脚本中的常规变量。[1]

使用 & 脚本块 ({ ... }) 代替脚本文件进行简洁演示:

PS> & { $foo = 'bar'; $env:foo = 'bar-env' }; "[$foo]", "[$env:foo]"
[]        # regular variable in the script [block] scope went out of scope
[bar-env] # environment variable is visible to caller (the whole *process*)

至于 1 的 PowerShell 等价物。(sh set_var.sh) 和 2. (./set_var.sh):

显式调用 PowerShell CLIpowershell.exe in Windows PowerShell, pwsh 在 PowerShell [Core],v6+ 中): 需要 运行 子进程.

中的脚本

注意:以下示例使用 pwsh,但同样适用于 powershell.exe(其 CLI 与 pwsh 的 CLI 基本相同,只有少数参数被修改添加到后者)。

在最简单的情况下,使用 -File(这是 PowerShell [Core] 中的隐含参数,但在 Windows PowerShell 中是必需的):

pwsh -File set_var.ps1  # PowerShell v6+: same as: pwsh set_var.ps1

但是请注意,您只能通过这种方式从脚本中获得 文本 输出(字符串),而不是丰富的 PowerShell 通常支持的对象

接收对象最简单方法 - 仅可从inside PowerShell获得[2] - 是 传递一个 脚本块 在其中调用脚本,它会自动生成CLI 输出 XML- 脚本输出对象的序列化表示,并导致调用会话自动反序列化这些表示:

pwsh { .\set_var.ps1 } 

注:

  • .\ 前缀是必需的,因为 PowerShell - 按照设计,作为一项安全功能 - 不允许 运行ning 脚本 仅文件名 来自 当前目录.

  • 使用 CLIXML 格式的基于 XML 的序列化 - 也用于 PowerShell 的远程处理和后台作业 - 在以下方面有限制保真度;除了 .NET 基本类型和一些众所周知的类型外,您可以获得原始对象的基于 [pscustomobject] 近似值 - 请参阅 .


[1] 但是,PowerShell 确实提供了跨会话范围边界设置变量的能力,例如$global:foo = 'bar' 设置会话全局变量或 Set-Variable foo bar -Scope 1 设置 调用者的 (父)作用域中的变量(当从脚本的顶级作用域调用时也将是全球范围)。

[2] 从 PowerShell 外部,您可以明确请求 CLIXML 格式(基于 XML 的对象序列化格式)的输出,即 -of Xml CLI 参数,但您必须自己解析 XML 并从中重建对象。