![](/img/trans.png)
[英]Putting functions in separate script and dot-sourcing them - what will the scope be
[英]Powershell running a scriptblock - scope, dot-sourcing
我想编写一个函数,该函数接受一个脚本块作为参数,并在调用它的范围内执行该脚本块。
Measure-Command 是我想要的行为的一个例子。 脚本块在与 Measure-Command 本身相同的范围内运行。 如果脚本块引用了此范围内的变量,则脚本可以更改它。
附件是一个示例脚本块,它增加了 $a 变量。 当被 Measure-Command 调用时,变量会增加。 但是当被 Wrapper 函数调用时,变量不会增加——除非我对 Wrapper 函数的调用和 Wrapper 函数本身都使用点源。
function Wrapper1
{
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "{0:HH:mm:ss} Start script" -f $startTime )
& $scriptBlock
$endTime = Get-Date
Write-Output ( "{0:HH:mm:ss} End script - {1:c} seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
}
function Wrapper2
{
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "{0:HH:mm:ss} Start script" -f $startTime )
. $scriptBlock
$endTime = Get-Date
Write-Output ( "{0:HH:mm:ss} End script - {1:c} seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
}
$a = 1
Write-Output "Initial state: `$a = $a"
Measure-Command { $a++ } | Out-Null
Write-Output "Measure-Command results: `$a = $a"
Wrapper1 { $a++ }
Write-Output "Wrapper1 results: `$a = $a"
. Wrapper1 { $a++ }
Write-Output "dot-sourced Wrapper1 results: `$a = $a"
Wrapper2 { $a++ }
Write-Output "Wrapper2 results: `$a = $a"
. Wrapper2 { $a++ }
Write-Output "dot-sourced Wrapper2 results: `$a = $a"
运行这段代码的结果是:
Initial state: $a = 1
Measure-Command results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00.0157407 seconds elapsed
dot-sourced Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper2 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
dot-sourced Wrapper2 results: $a = 3
虽然最后一个选项有效,但我想避免调用 Wrapper2 的点源语法。 这可能吗? Measure-Command 不使用点源语法,所以它似乎是可能的。
PetSerAl ,正如他惯常做的那样,在对这个问题的简短评论中提供了关键的指针:
将函数放在module 中,以及脚本块参数的点源调用,解决了这个问题:
$null = New-Module {
function Wrapper {
param($ScriptBlock)
. $ScriptBlock
}
}
$a = 1
Wrapper { $a++ }
$a
以上产生2
,证明脚本块在调用者的范围内执行。
有关为什么这样做以及为什么有必要的解释,请参阅相关问题的答案。
注意:上面的方法没有扩展到管道使用,在那里你需要传递脚本块,这些脚本块期望使用自动变量$_
来引用手头的对象(例如,
1, 2, 3 | Wrapper { $_ ... }
1, 2, 3 | Wrapper { $_ ... }
; 为了支持此用例,需要一种解决方法 - 请参阅此答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.