Fan*_*hou 10 powershell powershell-3.0
简短的问题:任何人都有关于ForEach-Object的-RemainingScripts参数的详细信息?
长问题:
我刚从上周开始学习PowerShell,我将通过每个Cmdlet来了解更多细节.基于公共文档,我们知道ForEach-Object可以有Begin-Process-End块,如下所示:
Get-ChildItem | foreach -Begin { "block1";
$fileCount = $directoryCount = 0} -Process { "block2";
if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}} -End {
"block3"; "$directoryCount directories and $fileCount files"}
Run Code Online (Sandbox Code Playgroud)
预期结果:"block1"和"block3"为1次,对于传入的每个项目重复"block2",并且dir计数/文件计数都是正确的.到现在为止还挺好.
现在,有趣的是,以下命令也起作用并给出完全相同的结果:
Get-ChildItem | foreach { "block1"
$fileCount = $directoryCount = 0}{ "block2";
if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}{
"block3"; "$directoryCount directories and $fileCount files"}
Run Code Online (Sandbox Code Playgroud)
只有3个ScriptBlocks传递给foreach.根据手册,第一个进入-Process(位置1).但剩下的2怎么样?根据手册,没有"位置2"的参数.所以我转向Trace-Command,发现后两个脚本块实际上是RemainingScripts,因为"IList with 2 elements".
BIND arg [$fileCount = $directoryCount = 0] to parameter [Process]
BIND arg [System.Management.Automation.ScriptBlock[]] to param [Process] SUCCESSFUL
BIND arg [System.Collections.ArrayList] to parameter [RemainingScripts]
BIND arg [System.Management.Automation.ScriptBlock[]] to param [RemainingScripts] SUCCESSFUL
Run Code Online (Sandbox Code Playgroud)
所以,如果我将命令更改为:
# No difference with/without the comma "," between the last 2 blocks
Get-ChildItem | foreach -Process { "block1"
$fileCount = $directoryCount = 0} -RemainingScripts { "block2";
if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}},{
"block3"; "$directoryCount directories and $fileCount files"}
Run Code Online (Sandbox Code Playgroud)
仍然,完全相同的结果.
正如您所注意到的,所有3个命令都给出了相同的结果.这提出了一个有趣的问题:后两个命令(隐式地)都指定了-Process,但ForEach-Object令人惊讶地最终使用-Process的参数作为"-Begin"!(脚本块在开头执行一次).
这个实验表明:
不过,以上所有只是我的猜测.我没有找到支持我猜测的文档
所以,最后我们回到我的简短问题:)任何人都有关于ForEach-Object的-RemainingScripts参数的详细信息?
谢谢.
我做了更多的研究,现在有信心在传入多个 ScriptBlock 时回答 -RemainingScripts 参数的行为。
如果您运行以下命令并仔细检查结果,您将找到模式。这不是很简单,但仍然不难弄清楚。
1..5 | foreach { "process block" } { "remain block" }
1..5 | foreach { "remain block" } -Process { "process block" }
1..5 | foreach { "remain block" } -End { "end block" } -Process { "process block" } -Begin { "begin block" }
1..5 | foreach { "remain block 1" } -End { "end block" } -Process { "process block" } { "remain block 2" }
1..5 | foreach { "remain block 1" } { "remain block 2" } -Process { "process block" } -Begin { "begin block" }
1..5 | foreach { "remain block 1" } { "remain block 2" } -Process { "process block" } { "remain block 3" }
1..5 | foreach { "process block" } { "remain block 1" } { "remain block 2" } -Begin { "begin block" }
1..5 | foreach { "process block" } { "remain block 1" } { "remain block 2" } { "remain block 3" }
Run Code Online (Sandbox Code Playgroud)
那么这里的模式是什么?
当传入单个 ScriptBlock 时:简单,它只是转到 -Process(最常见的用法)
当正好传入 2 个 ScriptBlocks 时,有 3 种可能的组合
如果我们运行这两个语句:
1..5 | foreach { "process block" } { "remain block" }
1..5 | foreach { "remain block" } -Process { "process block" }
# Both of them will return:
process block
remain block
remain block
remain block
remain block
remain block
Run Code Online (Sandbox Code Playgroud)
您会发现,这只是以下测试用例的一个特例:
当传入超过 2 个 ScriptBlocks 时,请遵循以下工作流程:
排序的结果是 ScriptBlocks 的集合。我们称这个集合为OrderedScriptBlocks
(内部)基于OrderedScriptBlocks重新绑定参数
让我们以这个例子
1..5 | foreach { "remain block 1" } { "remain block 2" } -Process { "process block" } { "remain block 3" }
Run Code Online (Sandbox Code Playgroud)
订单结果为:
{ "process block" } # new Begin
{ "remain block 1" } # new Process
{ "remain block 2" } # new Process
{ "remain block 3" } # new End
Run Code Online (Sandbox Code Playgroud)
现在执行结果完全可以预测:
process block
remain block 1
remain block 2
remain block 1
remain block 2
remain block 1
remain block 2
remain block 1
remain block 2
remain block 1
remain block 2
remain block 3
Run Code Online (Sandbox Code Playgroud)
这就是 -RemainingScripts 背后的秘密,现在我们了解了 ForEach-Object 的更多内部行为!
我仍然不得不承认没有文档支持我的猜测(不是我的错!),但是这些测试用例应该足以解释我描述的行为。
| 归档时间: |
|
| 查看次数: |
2522 次 |
| 最近记录: |