我正在尝试将字符串数组传递给write-host,并显式使用name
来写那些字符串:
$_
但是,它失败了:
输入对象不能绑定到该命令的任何参数,因为该命令不接受管道输入,或者该输入的属性与接受管道输入的任何参数都不匹配。 < / p>
此错误消息对我来说毫无意义,因为我完全有能力写作
'foo', 'bar', 'baz' | write-host $_
我希望两个管道都是相同的。显然,事实并非如此。那么,有什么区别呢?
答案 0 :(得分:2)
我希望两个管道都是相同的。
他们不是:
'foo', 'bar', 'baz' | write-host
它是以下内容的基于管道的等效项(在最终效果上等效,在技术上等效):
foreach ($str in 'foo', 'bar', 'baz') { Write-Host -Object $str }
也就是说,在命令Write-Host
中,通过管道-Object
通过参数{{1}隐式绑定到其-Object
参数 的输入。 }被声明为接受通过属性[Parameter(ValueFromPipeline=$true)]
'foo', 'bar', 'baz' | write-host $_
流水线处理开始之前,参数-在您的情况下为$_
-已绑定到参数 first :
由于$_
之前没有参数名称,因此它将按位置绑定到-隐含的-Object
参数。
然后,当管道处理开始时, pipeline 参数绑定不再找到要绑定的管道绑定Write-Host
参数,因为只有这样的参数-Object
已被约束,即已被自变量 $_
约束。
换句话说:您的命令错误地试图将-Object
参数绑定为两次; ;不幸的是,错误消息并没有清楚地表明这一点。 / p>
更大的一点是,仅在脚本块内 ($_
)中使用{ ... }
是有意义的,而每个输入对象。
在该上下文之外,$_
(或其别名,$PSItem
)通常没有值,因此不应使用。
虽然$_
最常用于传递给ForEach-Object
和Where-Object
cmdlet的脚本块中,但还有另一个有用的应用程序,最常见的是Rename-Item
cmdlet :一个delay-bind script-block argument:
# Example: rename *.txt files to *.dat files using a delay-bind script block:
Get-Item *.txt | Rename-Item -NewName { $_.BaseName + '.dat' }
也就是说,您没有传递 static 新名称到Rename-Item
,而是传递了针对每个输入对象评估的 script块-输入照常绑定到$_
的对象-启用动态行为。
但是,如链接答案中所述,此技术仅适用于同时具有(a)管道绑定和(b)不是 [object]
或[scriptblock]
的参数打字因此,假设输入了Write-Object
的{{1}}参数 -Object
,则该技术不有效:
[object]
因此,在这种情况下,基于管道的解决方案需要使用 # Try to enclose all inputs in [...] on output.
# !! DOES NOT WORK.
'foo', 'bar', 'baz' | write-host -Object { "[$_]" }
:
ForEach-Object
答案 1 :(得分:0)
您可以按iRon在评论中指出的方式使用它。 $_
或$PSItem
是正在处理的管道中的当前对象。通常,您会看到需要处理或脚本块的命令。您必须将Write-Host
命令包含在类似的处理块中。
'foo', 'bar', 'baz' | ForEach-Object {write-host $_}
以下是使用函数处理块的示例:
function write-stuff {
process { write-host $_ }
}
'foo', 'bar', 'baz' | write-stuff
bar
foo
hi