2012-07-27 143 views
3

在PowerShell中,似乎执行管道中的cmdlet的顺序不会以明显的方式执行。而不是每个cmdlet执行,然后将结果传递到管道中的下一个cmdlet,看起来在执行前一个cmdlet完成之前,cmdlet的单个输出对象将传递到下一个cmdlet的输入。下面证实了这一现象:流水线中ForEach-Object 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)) })包装块或者将一个块分配给一个变量,然后将其传递给后续的管道命令以避免这种行为,但是有没有办法对每个元素执行一个操作集合,然后将整个集合传递给管道中的下一个命令?

回答

4

这符合我对流水线如何处理对象的理解。在下一个项目被触摸之前,物体尽可能在管道中“尽可能”移动。有些cmdlet不使用“process”块,而是使用“end”块(例如,sort-object必须让所有项目实际执行排序),以便阻塞管道。其他人使用写输出(你的第二个$ _正在隐式执行)并保持管道移动。

+0

同意这一点;问题中的输出对我自己来说很直观。请注意,当您执行'(1..5 |%{Write-Host $ _; $ _})|时,输出会发生变化%{Write-Host([char]($ _ + 64))}'。这将导致'()'中的所有内容首先被执行,然后每个项目被交给外部管道。 – SpellingD 2012-07-27 20:42:47

+0

我记得Jeffrey Snover和Eric Meijer在谈论PowerShell和Monads时的一段视频(Channel 9?),Snover画了一个关于如何将东西压入管道的图表。我会看看我能否找到链接。 – 2012-07-27 20:46:32

+1

这不是很难找到。这里是[链接](http://channel9.msdn.com/Shows/Going+Deep/Expert-to-Expert-Erik-Meijer-and-Jeffrey-Snover-Inside-PowerShell) – 2012-07-27 20:48:05

1

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

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

而且,因为它是PowerShell的,它在这里的所有记载:

Get-Help about_pipelines 
+0

这应该是最后一个链接吗?它不起作用。 – 2017-01-21 21:58:35

+0

不是。这是一个PowerShell命令:'Get-Help about_pipelines'如果你没有在本地更新帮助,请使用Get-Help about_pipelines - 在线或搜索“about_pipelines” – Thanassis 2017-01-21 23:16:41