PowerShell:使用InputObject的ForEach-Object有什么意义? [英] PowerShell: What is the point of ForEach-Object with InputObject?

查看:266
本文介绍了PowerShell:使用InputObject的ForEach-Object有什么意义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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-ObjectInputObject似乎完全没有用.我对此不了解吗?

解决方案

对于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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆