电源外壳。管道命令和使用 Foreach-Object 之间的区别
Powershell. Difference between piping commands and using Foreach-Object
抱歉,如果这个问题已经得到解答,我可以找到类似的问题,但不是我需要问的确切问题。
举两个例子:
1. Get-Process -name msedge,putty | Stop-Process
2. Get-Process -name msedge,putty | Foreach-Object {Stop-Process $_}
两者都在做同样的操作。每个方法中使用的方法如何?从第一个示例只是为了代码 readability/aesthetics 而省略 Foreach-Object
构造的意义上说,它们是否相同?
第一个示例要求Cmdlet 支持通过管道绑定相关参数。在您的情况下,Stop-Process
会将流程对象从管道绑定到它的 -InputObject
参数。
您可以使用 get-help stop-process -Parameter *
检查并查看哪些参数具有“接受管道输入?”设置为真。
如果 Cmdlet 不支持相关参数值的绑定,您可以将其包裹 ForEach-Object
,就像您在第二个示例中所做的那样。通过这种方式,您可以使用自动变量 $_
将当前管道对象(或您从中派生的信息)“手动”绑定到相应的参数。
如果 Cmdlet 支持绑定来自管道的参数值,您应该使用什么方法?不幸的是,这取决于。可以编写行为不同的 Cmdlet,具体取决于参数值的绑定方式。让我来说明这一点:
function Test-BindingFoo {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline)]
[string[]]
$InputParameter
)
begin {
Write-Host "[BEGIN]"
}
process {
foreach ($value in $InputParameter) {
Write-Host "The current value is: $value"
}
}
end {
Write-Host "[END]"
}
}
如果使用管道绑定执行此 Cmdlet,函数的开始块将恰好执行一次:
❯ "foo1", "foo2" | Test-BindingFoo
[BEGIN]
The current value is: foo1
The current value is: foo2
[END]
如果您使用 ForEach-Object
每次对象通过管道时都会执行 Begin 块:
❯ "foo1", "foo2" | ForEach-Object { Test-BindingFoo $_ }
[BEGIN]
The current value is: foo1
[END]
[BEGIN]
The current value is: foo2
[END]
在良好实施的 Cmdlet 中,这里的差异应该无关紧要。但我发现,以我们在此处讨论的方式传入参数时,了解 Cmdlet 内部发生的情况很有用。
你也可以这样做,对进程对象(操作语句)使用kill方法:
Get-Process msedge,putty | Foreach-Object kill
# or
Get-Process msedge,putty | Foreach-Object -membername kill
抱歉,如果这个问题已经得到解答,我可以找到类似的问题,但不是我需要问的确切问题。
举两个例子:
1. Get-Process -name msedge,putty | Stop-Process
2. Get-Process -name msedge,putty | Foreach-Object {Stop-Process $_}
两者都在做同样的操作。每个方法中使用的方法如何?从第一个示例只是为了代码 readability/aesthetics 而省略 Foreach-Object
构造的意义上说,它们是否相同?
第一个示例要求Cmdlet 支持通过管道绑定相关参数。在您的情况下,Stop-Process
会将流程对象从管道绑定到它的 -InputObject
参数。
您可以使用 get-help stop-process -Parameter *
检查并查看哪些参数具有“接受管道输入?”设置为真。
如果 Cmdlet 不支持相关参数值的绑定,您可以将其包裹 ForEach-Object
,就像您在第二个示例中所做的那样。通过这种方式,您可以使用自动变量 $_
将当前管道对象(或您从中派生的信息)“手动”绑定到相应的参数。
如果 Cmdlet 支持绑定来自管道的参数值,您应该使用什么方法?不幸的是,这取决于。可以编写行为不同的 Cmdlet,具体取决于参数值的绑定方式。让我来说明这一点:
function Test-BindingFoo {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline)]
[string[]]
$InputParameter
)
begin {
Write-Host "[BEGIN]"
}
process {
foreach ($value in $InputParameter) {
Write-Host "The current value is: $value"
}
}
end {
Write-Host "[END]"
}
}
如果使用管道绑定执行此 Cmdlet,函数的开始块将恰好执行一次:
❯ "foo1", "foo2" | Test-BindingFoo
[BEGIN]
The current value is: foo1
The current value is: foo2
[END]
如果您使用 ForEach-Object
每次对象通过管道时都会执行 Begin 块:
❯ "foo1", "foo2" | ForEach-Object { Test-BindingFoo $_ }
[BEGIN]
The current value is: foo1
[END]
[BEGIN]
The current value is: foo2
[END]
在良好实施的 Cmdlet 中,这里的差异应该无关紧要。但我发现,以我们在此处讨论的方式传入参数时,了解 Cmdlet 内部发生的情况很有用。
你也可以这样做,对进程对象(操作语句)使用kill方法:
Get-Process msedge,putty | Foreach-Object kill
# or
Get-Process msedge,putty | Foreach-Object -membername kill