11

我了解 PowerShell 管道通过获取一个 cmdlet 的输出并将其作为输入传递给另一个 cmdlet 来工作。但它是如何做到这一点的呢?

第一个 cmdlet 是否完成,然后一次传递所有输出变量,然后由下一个 cmdlet 处理?

还是第一个 cmdlet 的每个输出一次获取一个,然后通过所有剩余的管道 cmdlet 运行它?

4

3 回答 3

13

您可以通过一个简单的脚本了解管道顺序是如何工作的:

function a {begin {Write-Host 'begin a'} process {Write-Host "process a: $_"; $_} end {Write-Host 'end a'}}
function b {begin {Write-Host 'begin b'} process {Write-Host "process b: $_"; $_} end {Write-Host 'end b'}}
function c { Write-Host 'c' }

1..3 | a | b | c

输出:

begin a
begin b
process a: 1
process b: 1
process a: 2
process b: 2
process a: 3
process b: 3
end a
end b
c
于 2013-06-26T20:29:47.113 回答
7

Powershell 管道以异步方式工作。这意味着第一个 cmdlet 的输出可立即用于第二个 cmdlet 的一个对象(即使第一个 cmdlet 尚未完成执行)。

例如,如果您运行以下行:

dir -recurse| out-file C:\a.txt

然后按 Control+C 停止执行,您将看到部分目录已写入文本文件。

一个更好的例子是下面的代码:(这对于删除驱动器 c 上的所有 .tmp 文件确实很有用:)

get-childitem c:\ -include *.tmp -recurse | foreach ($_) {remove-item $_.fullname}

每次 $_ 在第二个 cmdlet 中获取一个(单个文件)的值

于 2013-06-26T15:56:12.357 回答
3

到目前为止,这两个答案都为您提供了一些关于流水线的好信息。但是,还有更多要说的。

首先,为了直接解决您的问题,您提出了管道可能工作的两种可能方式。他们都是对的……取决于管道两侧的 cmdlet!但是,管道应该工作的方式更接近您的第二个概念:一次处理一个对象。(虽然不能保证一个对象会在下一个对象启动之前一直通过,因为管道中的每个组件都是异步的,正如 S Nash 提到的那样。)

那么“这取决于您的 cmdlet”是什么意思?如果您谈论的是 Microsoft 提供的 cmdlet,它们可能都按您的预期工作,尽可能高效地通过管道传递每个对象。但是,如果您谈论的是您编写的 cmdlet,则取决于您如何编写它们:编写无法进行正确流水线操作的 cmdlet 与编写成功的 cmdlet 一样容易!

有两种主要的失效模式:

  • 在将任何输出发送到管道之前生成所有输出,或
  • 在处理任何之前收集所有管道输入。

当然,您要争取的是在收到每个输入后立即处理它,并在确定后立即发出其输出。有关所有这些的详细示例,请参阅我刚刚在 Simple-Talk.com 上发表的文章《PowerShell 管道的来龙去脉》。

于 2015-11-07T00:55:39.340 回答