为什么不能在写入主机中使用$ _?

时间:2019-04-13 12:37:34

标签: powershell pipeline

我正在尝试将字符串数组传递给write-host,并显式使用name来写那些字符串:

$_

但是,它失败了:

  

输入对象不能绑定到该命令的任何参数,因为该命令不接受管道输入,或者该输入的属性与接受管道输入的任何参数都不匹配。 < / p>

此错误消息对我来说毫无意义,因为我完全有能力写作

'foo', 'bar', 'baz' | write-host $_

我希望两个管道都是相同的。显然,事实并非如此。那么,有什么区别呢?

2 个答案:

答案 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-ObjectWhere-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