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

问题描述 投票:0回答:2

在 bash 中,如果我在脚本中定义变量(例如,

set_var.sh
),我可以选择这些定义在“运行”脚本后是否保留。 这将取决于我如何“运行”脚本,选项是:

  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


bash powershell variables scope environment-variables
2个回答
4
投票

补充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 - 按照设计,作为一项安全功能 - 不允许通过

    当前目录
    中的仅文件名运行脚本。

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

    近似值
    - 请参阅这个答案


[1] 但是,PowerShell 确实提供了跨会话范围边界设置变量的能力,例如

$global:foo = 'bar' 设置会话全局变量或

Set-Variable foo bar -Scope 1
调用者
(父级)作用域中设置变量(从脚本的顶级作用域调用时也将是全局作用域)。

[2] 从 PowerShell 外部,您可以显式请求 CLIXML 格式(基于 XML 的对象序列化格式)的输出,即使用

-of Xml CLI 参数,但您必须自己解析 XML 并重建来自它的物体。


    


3
投票
.

-

点源运算符 - 在调用者的作用域中执行脚本或命令,从而在执行后保留所有变量:
# 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

© www.soinside.com 2019 - 2024. All rights reserved.