Powershell中的管道

我在about_Pipelines 上阅读了有关管道在 PowerShell 中的工作原理的信息,并了解到管道一次传送一个对象。

所以这

Get-Service | Format-Table -Property Name, DependentServices

与此不同

Format-Table -InputObject (Get-Service) -Property Name, DependentServices

所以在这里,按照解释,在第一种情况下,一次Format-Table在一个对象上工作,在第二个例子中,Format-Table工作在一个对象数组上。如果我错了,请纠正我。

如果是这种情况,那么我想知道Sort-Object需要处理数据集合的其他 cmdlet 是如何使用管道字符的。

当我做 :

Get-Service | Sort-Object

Sort-Object如果它一次只处理一个对象,它如何能够排序。因此,假设有 100 个服务对象要传递给Sort-Object。会Sort-Object被调用 100 次(每次调用一个对象)?而且,这将如何产生我在屏幕上看到的排序结果。

回答

Sort-Object(以及其他需要在输出任何内容之前评估所有输入对象的cmdlet )通过一个一个收集输入对象来工作,然后在上游 cmdlet(Get-Service在本例中)完成发送输入之前不做任何实际工作。

这是如何运作的?好吧,让我们尝试Sort-Object使用 PowerShell 函数重新创建。

为此,我们首先需要了解一个 cmdlet 由 3 个独立的例程组成:

  • Begin-Begin管道中每个 cmdlet的例程在其他任何事情发生之前被调用一次
  • Process-每次从上游命令接收输入时,都会在每个 cmdlet 上调用此例程
  • End- 一旦上游命令被调用End并且没有更多的输入项Process需要处理,就会调用它

(这些是 PowerShell函数定义中使用的块标签名称- 在二进制 cmdlet 中,您将覆盖BeginProcessing, ProcessRecord, EndProcessingcmdlet 方法的实现)

所以,为了“收集”每一个输入项,我们需要在Process我们的命令块中添加一些逻辑,然后我们可以把对End块中所有项进行操作的代码:

function Sort-ObjectCustom
{
  param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [object[]]$InputObject
  )

  begin {
    # Let's use the `begin` block to create a list that'll hold all the input items
    $list = [System.Collections.Generic.List[object]]::new()

    Write-Verbose "Begin was called"
  }

  process {
    # Here we simply collect all input to our list
    $list.AddRange($InputObject)

    Write-Verbose "Process was called [InputObject: $InputObject]"
  }

  end {
    # The `end` block is only ever called _after_ we've collected all input
    # Now we can safely sort it
    $list.Sort()

    Write-Verbose "End was called"

    # and output the results
    return $list
  }
}

如果我们使用 调用我们的新命令-Verbose,我们将看到如何一一收集输入:

function Sort-ObjectCustom
{
  param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [object[]]$InputObject
  )

  begin {
    # Let's use the `begin` block to create a list that'll hold all the input items
    $list = [System.Collections.Generic.List[object]]::new()

    Write-Verbose "Begin was called"
  }

  process {
    # Here we simply collect all input to our list
    $list.AddRange($InputObject)

    Write-Verbose "Process was called [InputObject: $InputObject]"
  }

  end {
    # The `end` block is only ever called _after_ we've collected all input
    # Now we can safely sort it
    $list.Sort()

    Write-Verbose "End was called"

    # and output the results
    return $list
  }
}

有关如何为二进制 cmdlet 实现管道输入处理例程的详细信息,请参阅“如何覆盖输入处理”。

有关如何在函数中利用相同管道语义的更多信息,请参阅about_Functions_Advanced_Methods和相关帮助主题


以上是Powershell中的管道的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>