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和相关帮助主题