如何在管道中执行ForEach-Object cmdlet的顺序?

时间:2012-07-27 18:59:13

标签: powershell pipeline

在PowerShell中,似乎没有以明显的方式执行管道中cmdlet的执行顺序。而不是每个cmdlet执行然后将结果传递给管道中的下一个cmdlet,似乎在执行上一个cmdlet完成之前,cmdlet的各个输出对象将传递到下一个cmdlet的输入。以下证实了这种行为:

1..5 | %{ Write-Host $_; $_ } | %{ Write-Host ([char]($_ + 64)) }

打印

1
A
2
B
3
C
4
D
5
E

似乎正在发生的事情是ForEach-Object cmdlet的每次执行都将在迭代之前执行其脚本块以及其管道中的每个后续命令

这是实际发生的事情吗?这种行为是在任何地方记录的吗?是否适用于所有迭代cmdlet,例如ForEach-Object(例如Where-Object等)?

我知道我可以将一个片段包装在一个表达式((1..5 | %{ Write-Host $_; $_ }) | %{ Write-Host ([char]($_ + 64)) })中,或者将一个片段分配给一个变量然后将其传递给后续的管道命令以避免这种行为,但是有没有办法对每个变量执行操作集合的元素,然后将整个集合传递给管道中的下一个命令?

2 个答案:

答案 0 :(得分:4)

这符合我对管道如何处理对象的理解。在触摸下一个项目之前,对象在管道中“尽可能远”地移动。某些cmdlet不使用“进程”块,而是出于必要而使用“结束”块(例如,sort-object必须让所有项目实际执行排序),因此它们会阻塞管道。其他人使用写输出(你的第二个$ _隐式执行)并保持管道移动。

答案 1 :(得分:1)

每个物体尽可能地穿过管道。这就是为什么每个cmdlet都应该将其输出直接写入管道而不是将其累积到某个内部存储中,除非它必须像Sort-Object一样处理所有输入。

它也有一些有趣的副作用。例如,Get-Member cmdlet在从管道获取输入时给出不同的输出,如果从InputObject参数获得输入则不同。

而且,因为它是PowerShell,所有这些都记录在这里:

Get-Help about_pipelines