documentation for ForEach-object说:“当将InputObject
参数与ForEach-Object
一起使用时,ForEach-Object
值被视为一个对象。”这种行为很容易直接观察到:
InputObject
这似乎很奇怪。如果没有“每个”要做的“ ForEach”有什么意义?真的没有办法让PS C:\WINDOWS\system32> ForEach-Object -InputObject @(1, 2, 3) {write-host $_}
1 2 3
直接作用于数组的各个元素而无需管道吗?如果不是,则ForEach-object
与ForEach-Object
似乎完全没有用。我对此不了解吗?
答案 0 :(得分:2)
Bender the Greatest's helpful answer很好地解释了当前行为。
对于绝大多数cmdlet,使用-InputObject
参数的直接确实毫无意义,并且应将参数视为实现细节< / em>的唯一目的是促进管道输入。
还有例外 ,例如Get-Member
cmdlet,直接使用
-InputObject
可以检查集合类型本身,而通过管道提供该集合将报告有关其元素的类型的信息。
鉴于当前的工作方式,很遗憾,-InputObject
在大多数cmdlet的帮助主题中具有突出的功能以及“真实”参数,并且没有用足够清晰(在撰写本文时):描述中应清楚地传达以下信息:“不要直接使用此参数,而应使用管道”。
This GitHub issue提供了哪些cmdlet如何直接处理
-InputObject
参数的分类概述。
退后一步:
从技术上讲,这是一项重大更改,对于-InputObject
参数(或任何管道绑定参数)来说,默认情况下接受并枚举的Line 11: Typo in component lifecycle method declaration react/no-typos
参数(即使它们是通过直接参数 传递,而不是通过管道传递,方式对实现命令是透明的。
这会将直接参数输入与管道输入相提并论,前者的额外好处是可以更快地处理已经在内存中的集合。
答案 1 :(得分:1)
对于ForEach-Object
或任何旨在对集合进行操作的cmdlet,将-InputObject
用作直接参数是没有意义的,因为该cmdlet旨在对集合进行操作,需要一次展开并处理一个元素。但是,我也不会将参数称为“无用的”,因为它仍然需要定义,因此可以将其设置为允许通过管道输入。
-InputObject
is, by convention, a generic parameter name for what should be considered to be pipeline input.这是一个设置了[Parameter(ValueFromPipeline = $true)]
的参数,因此更适合从管道中获取输入,而不是作为直接参数传递。将其作为直接参数传递的主要缺点是the collection is not guaranteed to be unwrapped,并且可能表现出某些其他不良行为。从上面链接到的about_pipelines
页面上:
将多个对象通过管道传递给命令时, PowerShell一次将对象发送给命令。使用命令参数时,对象将作为单个数组对象发送。这种微小的差异会带来重大后果。
要用不同的词来解释以上引用,通过管道传递集合(例如数组或列表)将自动展开该集合,并将其一次一次传递给管道中的下一个命令。 该cmdlet本身不会展开-InputObject
,数据一次只能传递一个元素。这就是为什么在将集合直接传递到-InputObject
参数时可能会看到问题的原因-因为该cmdlet可能不是设计用来展开集合本身的,,它希望将每个集合元素传递给它是零散的。
# Array of hashes with a common key
$myHash = @{name = 'Alex'}, @{name='Bob'}, @{name = 'Sarah'}
# This works as intended
$myHash | Where-Object { $_.name -match 'alex' }
上面的代码按预期输出以下内容:
Name Value
---- -----
name Alex
但是,如果您像这样直接将哈希作为InputArgument
传递:
Where-Object -InputObject $myHash { $_.name -match 'alex' }
它返回整个集合,因为-InputObject
从未通过管道传递时一直处于展开状态,但是在这种情况下,$_.name -match 'alex'
仍返回true。换句话说,在将集合作为-InputObject
的直接参数提供时, 将其视为单个对象,而不是每次对集合中的每个元素执行一次 。当针对该数据集检查错误条件时,这也可以使外观正常工作:
Where-Object -InputObject $myHash { $_.name -match 'frodo' }
最终什么也不返回,因为即使在这种情况下,frodo
也不是哈希集合中任何name
键的值。
简而言之,如果某些人希望输入作为管道输入传递,那么这样做通常是一个更安全的选择,即使并非总是如此,尤其是在传递集合时。但是,如果您使用的是非集合,那么选择直接使用-InputObject
参数就不会有问题。