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

Powershell ForEach Object cmdlet在管道中的执行顺序如何?,powershell,pipeline,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对象cmdlet的每次执行都将在迭代之前执行其脚本块及其管道

在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对象
cmdlet的每次执行都将在迭代之前执行其脚本块及其管道中的每个后续命令

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


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

这与我对管道如何处理对象的理解相符。在触摸下一个项目之前,对象在管道中移动“尽可能远”。有些cmdlet不使用“process”块,而是出于必要使用“end”块(例如,sort对象必须具有所有项才能实际执行排序),因此它们会阻塞管道。其他的则使用写输出(第二个$uu隐式地执行),并保持管道移动。

每个对象都尽可能地在管道中移动。这就是为什么每个cmdlet都应该将其输出直接写入管道,而不是将其累积到某些内部存储中,除非它必须像Sort对象一样同时处理所有输入

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

而且,因为它是PowerShell,所以这里都有文档记录:

Get-Help about_pipelines

同意这一点;问题中的输出对我来说是直观的。注意当您执行
(1..5 |%{Write Host$\u;$\ u})|%{Write Host([char]($\u64))}
时输出是如何变化的。这将导致首先执行
()
中的所有内容,然后这些内容中的每一项都被传递到外部管道。我记得Jeffrey Snover和Eric Meijer在视频(第9频道?)中谈到PowerShell和Monads,Snover在视频中绘制了一张东西如何被推下管道的图表。我看看能不能找到链接。不难找到。这是我的经验和测试结果。您是否能够找到有关此行为的任何文档,以及如何知道管道中的命令是否会阻止管道?Bruce Payette在《PowerShell in Action第二版》中的一节“管道和流行为”(第2.5.1节,第56-57页)中对此进行了讨论。如果你想了解PowerShell的机制,我不能推荐任何一本书。这应该是最后的链接吗?没用,没用。这是一个PowerShell命令:
Get Help about_pipelines
如果您尚未在本地更新帮助,请使用
Get Help about_pipelines-Online
或搜索“about_pipelines”