PowerShell:使用InputObject的ForEach-Object有什么意义? [英] PowerShell: What is the point of ForEach-Object with InputObject?
问题描述
ForEach对象的文档表示将InputObject
参数与ForEach-Object
一起使用时,将InputObject
值视为单个对象,而不是将管道命令结果传递到ForEach-Object
."这种行为很容易直接观察到:
PS C:\WINDOWS\system32> ForEach-Object -InputObject @(1, 2, 3) {write-host $_}
1 2 3
这似乎很奇怪.如果没有每个"都可以做的"ForEach"有什么意义呢?真的没有办法让ForEach-object
直接在不使用管道的情况下直接作用于数组的各个元素吗?如果不是,则ForEach-Object
与InputObject
似乎完全没有用.我对此不了解吗?
对于ForEach-Object
或任何旨在对集合进行操作的cmdlet,使用
-InputObject
作为直接参数不会'这是有意义的,因为cmdlet旨在对集合进行操作,该集合需要一次展开和处理一个元素.但是,我也不会将参数称为无用的",因为它仍然需要定义,因此可以将其设置为允许通过管道输入.
为什么要这样?
-InputObject
按照惯例是通用参数名称,应被视为管道输入.设置了[Parameter(ValueFromPipeline = $true)]
的参数,因此更适合从管道中获取输入,而不是作为直接参数传递.将其作为直接参数传递的主要缺点是documentation for ForEach-object says "When you use the InputObject
parameter with ForEach-Object
, instead of piping command results to ForEach-Object
, the InputObject
value is treated as a single object." This behavior can easily be observed directly:
PS C:\WINDOWS\system32> ForEach-Object -InputObject @(1, 2, 3) {write-host $_}
1 2 3
This seems weird. What is the point of a "ForEach" if there is no "each" to do "for" on? Is there really no way to get ForEach-object
to act directly on the individual elements of an array without piping? if not, it seems that ForEach-Object
with InputObject
is completely useless. Is there something I don't understand about that?
In the case of ForEach-Object
, or any cmdlet designed to operate on a collection, using the -InputObject
as a direct parameter doesn't make sense because the cmdlet is designed to operate on a collection, which needs to be unrolled and processed one element at a time. However, I would also not call the parameter "useless" because it still needs to be defined so it can be set to allow input via the pipeline.
Why is it this way?
-InputObject
is, by convention, a generic parameter name for what should be considered to be pipeline input. It's a parameter with [Parameter(ValueFromPipeline = $true)]
set to it, and as such is better suited to take input from the pipeline rather passed as a direct argument. The main drawback of passing it in as a direct argument is that the collection is not guaranteed to be unwrapped, and may exhibit some other behavior that may not be intended. From the about_pipelines
page linked to above:
When you pipe multiple objects to a command, PowerShell sends the objects to the command one at a time. When you use a command parameter, the objects are sent as a single array object. This minor difference has significant consequences.
To explain the above quote in different words, passing in a collection (e.g. an array or a list) through the pipeline will automatically unroll the collection and pass it to the next command in the pipeline one at a time. The cmdlet does not unroll -InputObject
itself, the data is delivered one element at a time. This is why you might see problems when passing a collection to the -InputObject
parameter directly - because the cmdlet is probably not designed to unroll a collection itself, it expects each collection element to be handed to it in a piecemeal fashion.
Consider the following example:
# Array of hashes with a common key
$myHash = @{name = 'Alex'}, @{name='Bob'}, @{name = 'Sarah'}
# This works as intended
$myHash | Where-Object { $_.name -match 'alex' }
The above code outputs the following as expected:
Name Value
---- -----
name Alex
But if you pass the hash as InputArgument
directly like this:
Where-Object -InputObject $myHash { $_.name -match 'alex' }
It returns the whole collection, because -InputObject
was never unrolled as it is when passed in via the pipeline, but in this context $_.name -match 'alex'
still returns true. In other words, when providing a collection as a direct parameter to -InputObject
, it's treated as a single object rather than executing each time against each element in the collection. This can also give the appearance of working as expected when checking for a false condition against that data set:
Where-Object -InputObject $myHash { $_.name -match 'frodo' }
which ends up returning nothing, because even in this context frodo
is not the value of any of the name
keys in the collection of hashes.
In short, if something expects the input to be passed in as pipeline input, it's usually, if not always, a safer bet to do it that way, especially when passing in a collection. However, if you are working with a non-collection, then there is likely no issue if you opt to use the -InputObject
parameter directly.
这篇关于PowerShell:使用InputObject的ForEach-Object有什么意义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!