Pal*_*cil 8 powershell environment-variables
目的
将环境变量更改隔离到代码块.
背景
如果我想创建一个批处理脚本来运行需要环境变量集的命令,我知道我可以这样做:
setlocal
set MYLANG=EN
my-cmd dostuff -o out.csv
endlocal
Run Code Online (Sandbox Code Playgroud)
但是,当我需要使用shell脚本语言时,我倾向于使用PowerShell.我知道如何设置环境变量($env:TEST="EN"),当然这只是一个简单的例子.但是,我不确定如何使用批处理脚本实现相同的效果.令人惊讶的是,我也没有看到任何问题.
我知道设置的东西$env:TEST="EN"是进程范围的,但如果我在单个终端会话中使用脚本作为小实用程序,则这是不实际的.
我目前的方法:
setlocal.但那不是一个小虫......我希望.$env:似乎没有太大的不同$global:)函数范围并不胜过引用 $env:
$env:TEST="EN"
function tt {
$env:TEST="GB"
($env:TEST)
}
($env:TEST)
tt
($env:TEST)
Run Code Online (Sandbox Code Playgroud)
输出:
C:\Users\me> .\eg.ps1
EN
GB
GB
Run Code Online (Sandbox Code Playgroud)
在批处理文件,所有的壳变量是环境变量太多; 因此,也setlocal ... endlocal为环境变量提供了局部作用域。
相比之下,在PowerShell中,外壳变量(如$var)是不同的环境变量(例如,$env:PATH) -一个区别是通常有利的。
鉴于最小的设置环境变量的作用域是当前过程-因此整个的PowerShell会话,你必须管理一个较小的自定义范围手动,如果你想这样做的过程(这是setlocal ... endlocal在做cmd.exe,为此PowerShell有没有内置等效项;对于自定义范围的shell变量,请使用& { $var = ...; ... }):
为了稍微减轻痛苦,您可以使用脚本块 ( { ... }) 来提供命令的独特视觉分组,在调用时&还会创建一个新的本地范围,以便任何 aux. 您在脚本块中定义的变量会自动超出范围(您可以将其写为带有;-separated 命令的一行):
& {
$oldVal, $env:MYLANG = $env:MYLANG, 'EN'
my-cmd dostuff -o out.csv
$env:MYLANG = $oldVal
}
Run Code Online (Sandbox Code Playgroud)
更简单地说,如果没有MYLANG必须恢复的先前存在的值:
& { $env:MYLANG='EN'; my-cmd dostuff -o out.csv; $env:MYLANG=$null }
Run Code Online (Sandbox Code Playgroud)
$oldVal, $env:MYLANG = $env:MYLANG, 'EN'在将值更改为$env:MYLANG的$oldVal同时保存in的旧值(如果有)'EN';这种同时分配给多个变量的技术(在某些语言中称为解构分配)在Get-Help about_Assignment_Operators“分配多个变量”一节中进行了解释。
一个更合适、更健壮但更冗长的解决方案是使用try { ... } finally { ... }:
try {
# Temporarily set/create $env:MYLANG to 'EN'
$prevVal = $env:MYLANG; $env:MYLANG = 'EN'
my-cmd dostuff -o out.csv # run the command(s) that should see $env:MYLANG as 'EN'
} finally { # remove / restore the temporary value
# Note: if $env:MYLANG didn't previously exist, $prevVal is $null,
# and assigning that back to $env:MYLANG *removes* it, as desired.
$env:MYLANG = $prevVal
}
Run Code Online (Sandbox Code Playgroud)
但是请注意,如果您只使用临时修改的环境调用外部程序,则不需要try/ catch,因为从 PowerShell 7.1 开始,外部程序永远不会导致 PowerShell 错误,尽管将来可能会发生变化。
为了促进这种方法,这个相关问题的答案提供了便利功能
Invoke-WithEnvironment,它允许您编写与以下相同的调用:
# Define env. var. $env:MYLANG only for the duration of executing the commands
# in { ... }
Invoke-WithEnvironment @{ MYLANG = 'EN' } { my-cmd dostuff -o out.csv }
Run Code Online (Sandbox Code Playgroud)
通过使用辅助进程并仅在那里设置瞬态环境变量,
您无需在调用后恢复环境
但是您付出了性能损失,并且增加了调用复杂性。
使用辅助。cmd.exe过程:
cmd /c "set `"MYLANG=EN`" & my-cmd dostuff -o out.csv"
Run Code Online (Sandbox Code Playgroud)
笔记:
"..."选择了外部引用,以便您可以在命令中引用 PowerShell 变量;嵌入"必须然后转义为`"
此外,目标命令的参数必须根据cmd.exe的规则传递(与手头的简单命令没有区别)。
使用辅助。子 PowerShell 会话:
# In PowerShell *Core*, use `pwsh` in lieu of `powershell`
powershell -nop -c { $env:MYLANG = 'EN'; my-cmd dostuff -o out.csv }
Run Code Online (Sandbox Code Playgroud)
笔记:
启动另一个 PowerShell 会话的开销很大。
脚本块 ( { ... }) 的输出在调用范围内进行序列化和反序列化;对于字符串输出,这无关紧要,但是复杂的对象(例如[System.IO.FileInfo]反序列化为原始对象的模拟)(可能有也可能没有问题)。
| 归档时间: |
|
| 查看次数: |
2215 次 |
| 最近记录: |