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

Bash PowerShell通过脚本实现环境变量范围内的灵活性,bash,powershell,variables,scope,environment-variables,Bash,Powershell,Variables,Scope,Environment Variables,在bash中,如果我在脚本中定义了一个变量,比如set_var.sh,我可以选择在运行脚本后这些定义是否保持不变。 这将取决于我如何运行脚本,选项包括: sh set_var.sh变量不会持续存在 ./set_var.sh变量不会持续存在,与第1点相同 源集合_var.sh变量持续存在 这与导出到环境中的变量或不在set_var.sh中的变量无关 对于PS和$env变量,是否可以使用PowerShell 5.1脚本实现与上面第1项和第3项相同的功能 有关说明,请参见下面的1 编辑: 根据Math

在bash中,如果我在脚本中定义了一个变量,比如set_var.sh,我可以选择在运行脚本后这些定义是否保持不变。 这将取决于我如何运行脚本,选项包括:

sh set_var.sh变量不会持续存在 ./set_var.sh变量不会持续存在,与第1点相同 源集合_var.sh变量持续存在 这与导出到环境中的变量或不在set_var.sh中的变量无关

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

有关说明,请参见下面的1

编辑:

根据Mathias R.Jessen的回答,等同于上述第3项的是dot采购。 还有一个上面没有提到的中间情况,也许在bash中也有一种方法可以做到这一点,在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持久性/非持久性变量示例

我的脚本集_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


你想要什么-在调用方的作用域中执行脚本或命令,从而在执行后保留所有变量:

设置变量ps1 $TEST_VAR=123 script.ps1 . $PSScriptRoot/set_vars.ps1 echo$TEST_VAR输出123 要避免本地定义的变量在执行后持久化,请按原样执行脚本,或显式使用&invocation运算符:

# script.ps1
& $PSScriptRoot/set_vars.ps1
echo $TEST_VAR 
# outputs an empty string, assuming $TEST_VAR was not already defined in the callers scope
你想要什么-在调用方的作用域中执行脚本或命令,从而在执行后保留所有变量:

设置变量ps1 $TEST_VAR=123 script.ps1 . $PSScriptRoot/set_vars.ps1 echo$TEST_VAR输出123 要避免本地定义的变量在执行后持久化,请按原样执行脚本,或显式使用&invocation运算符:

# 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不同,它在进程中运行-保留环境变量更改,但不保留脚本中的常规变量。[1]

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

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:

要在子进程中运行脚本,需要显式调用Windows PowerShell中PowerShell[Core],v6+:中的PowerShell CLI

注意:以下示例使用pwsh,但同样适用于powershell.exe,其CLI与pwsh基本相同,后者仅添加了几个参数

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

pwsh -File set_var.ps1  # PowerShell v6+: same as: pwsh set_var.ps1
但是请注意,您只能通过这种方式从脚本中获取文本输出字符串,而不是PowerShell通常支持的富对象

接收对象的最简单方法(仅从PowerShell内部提供[2])是传递一个脚本块,在该脚本块中调用该脚本,该脚本块会自动使脚本输出对象的CLI输出XML序列化表示形式,并使调用会话自动反序列化这些表示:

pwsh { .\set_var.ps1 } 
注:

.\前缀是必需的,因为PowerShell(按设计,作为一种安全功能)不允许仅通过当前目录中的文件名来运行脚本

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

[1] 但是,PowerShell确实提供跨会话范围边界设置变量的功能,例如,$global:foo='bar'设置会话全局变量,或设置变量foo bar-scope 1在调用方的父范围中设置变量,当从脚本的顶级范围调用时,该父范围也将是全局范围

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

补充:

关于您的编辑:

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

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

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:

要在子进程中运行脚本,需要显式调用Windows PowerShell中PowerShell[Core],v6+:中的PowerShell CLI

注:以下示例使用pwsh,b 但powershell.exe的CLI与pwsh的基本相同,后者只添加了几个参数

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

pwsh -File set_var.ps1  # PowerShell v6+: same as: pwsh set_var.ps1
但是请注意,您只能通过这种方式从脚本中获取文本输出字符串,而不是PowerShell通常支持的富对象

接收对象的最简单方法(仅从PowerShell内部提供[2])是传递一个脚本块,在该脚本块中调用该脚本,该脚本块会自动使脚本输出对象的CLI输出XML序列化表示形式,并使调用会话自动反序列化这些表示:

pwsh { .\set_var.ps1 } 
注:

.\前缀是必需的,因为PowerShell(按设计,作为一种安全功能)不允许仅通过当前目录中的文件名来运行脚本

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

[1] 但是,PowerShell确实提供跨会话范围边界设置变量的功能,例如,$global:foo='bar'设置会话全局变量,或设置变量foo bar-scope 1在调用方的父范围中设置变量,当从脚本的顶级范围调用时,该父范围也将是全局范围


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

这相当于我的第3项持久变量。1的等价物是什么?@sancho.srestinstatemonicacellio,这只是在执行脚本时使用或不使用&operator的默认行为。请参见OP的编辑。使用或不使用®;的默认行为是一种中间情况,而不是1。@sancho.srestinstatemonicacellio这是什么意思?&或者简单地使用运行它。`在*script*范围内运行,这是PowerShell中脚本的一个特殊范围,用于本地化脚本中的变量。如果您想要像local-local一样,可以尝试在&`内部进行dotsourcing,以使它在与&{.Path\to\File}类似的本地文件中可用。请看,这相当于我的第3项持久变量。1的等价物是什么?@sancho.srestinstatemonicacellio,这只是在执行脚本时使用或不使用&operator的默认行为。请参见OP的编辑。使用或不使用®;的默认行为是一种中间情况,而不是1。@sancho.srestinstatemonicacellio这是什么意思?&或者简单地使用运行它。`在*script*范围内运行,这是PowerShell中脚本的一个特殊范围,用于本地化脚本中的变量。如果您想要像local-local一样,可以尝试在&`内部进行dotsourcing,以使它在与&{.Path\to\File}类似的本地文件中可用。看见