在 bash 中,如果我在脚本中定义变量(例如,
set_var.sh
),我可以选择这些定义在“运行”脚本后是否保留。
这将取决于我如何“运行”脚本,选项是:
sh set_var.sh
(变量不会持久)./set_var.sh
(变量不持久,与第 1 点相同)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
补充Mathias的有用答案:
关于您的编辑:
它是脚本的 直接调用/通过
&
进行调用 - 与 sh
/ bash
不同,运行于 进程中 - 保留对 环境变量的更改,但不保留对 常规的更改脚本中的变量。[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*)
至于 PowerShell 相当于 1。(
sh set_var.sh
)
2.(./set_var.sh
):
显式调用 PowerShell CLI(Windows PowerShell 中为
powershell.exe
,PowerShell [Core]、v6+ 中为 pwsh
):需要在 子进程中运行脚本。
注意:以下示例使用
pwsh
,但同样适用于 powershell.exe
(其 CLI 与 pwsh
基本相同,仅在后者中添加了一些参数)。
在最简单的情况下,使用
-File
(这是 PowerShell [Core] 中的隐含参数,但在 Windows PowerShell 中是必需的):
pwsh -File set_var.ps1 # PowerShell v6+: same as: pwsh set_var.ps1
但是请注意,您只能通过这种方式从脚本中获得文本输出(字符串),而不是 PowerShell 通常支持的丰富的对象。
接收 objects 的最简单方法 - 只能从 inside PowerShell 获得[2] - 是 传递一个 脚本块,在其中调用脚本,这会自动生成 CLI 输出脚本输出对象的 XML 序列化表示,并导致这些表示由调用会话自动反序列化:
pwsh { .\set_var.ps1 }
注:
.\
前缀是必要的,因为PowerShell - 按照设计,作为一项安全功能 - 不允许通过
当前目录中的仅文件名运行脚本。
类型保真度方面存在限制;除了 .NET 原始类型和一些众所周知的类型之外,您可以获得原始对象的基于[pscustomobject]
的
近似值- 请参阅这个答案。
$global:foo = 'bar'
设置会话全局变量或
Set-Variable foo bar -Scope 1
在 调用者(父级)作用域中设置变量(从脚本的顶级作用域调用时也将是全局作用域)。 [2] 从 PowerShell 外部,您可以显式请求 CLIXML 格式(基于 XML 的对象序列化格式)的输出,即使用
-of Xml
CLI 参数,但您必须自己解析 XML 并重建来自它的物体。
.
-
点源运算符 - 在调用者的作用域中执行脚本或命令,从而在执行后保留所有变量:# 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