【问题标题】:How does the order of execution of the ForEach-Object cmdlet in a pipeline work?管道中 ForEach-Object cmdlet 的执行顺序如何工作?
【发布时间】:2012-07-27 18:59:12
【问题描述】:

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

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

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

【问题讨论】:

    标签: powershell pipeline


    【解决方案1】:

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

    【讨论】:

    • 同意这个;问题中的输出对我来说很直观。注意(1..5 | %{ Write-Host $_; $_ }) | %{ Write-Host ([char]($_ + 64))} 时输出的变化。这将导致() 中的所有内容首先执行,然后将这些项目中的每一项都交给外部管道。
    • 我记得一个视频(第 9 频道?),Jeffrey Snover 和 Eric Meijer 谈论 PowerShell 和 Monads,其中 Snover 绘制了一张图表,说明了东西是如何被推下管道的。我看看能不能找到链接。
    • 并不难找到。这是link
    • 这也符合我的经验和测试。您是否能够找到有关此行为的任何文档,以及如何知道管道中的命令是否会阻塞管道?
    • Bruce Payette 在 PowerShell in Action 2nd Edition 的“管道和流行为”一节(第 2.5.1 节,第 56-57 页)中讨论了这一点。如果你想了解 PowerShell 的机制,我推荐任何一本书。
    【解决方案2】:

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

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

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

    Get-Help about_pipelines
    

    【讨论】:

    • 那应该是最后的链接吗?它不起作用。
    • 不。这是一个 PowerShell 命令:Get-Help about_pipelines 如果您尚未在本地更新帮助,请使用 Get-Help about_pipelines -Online 或搜索“about_pipelines”
    猜你喜欢
    • 2021-06-05
    • 1970-01-01
    • 2011-12-06
    • 2016-05-19
    • 2020-07-02
    • 2014-02-13
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    相关资源
    最近更新 更多