【问题标题】:Why can't I use $_ in write-host?为什么我不能在 write-host 中使用 $_?
【发布时间】:2019-04-13 12:37:33
【问题描述】:

我正在尝试将字符串数组通过管道传输到 write-host 并明确使用 $_ 来写入这些字符串:

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

但是,它失败了:

输入对象不能绑定到命令的任何参数,因为命令不接受管道输入,或者输入及其属性不匹配任何接受管道输入的参数。

这个错误信息对我来说毫无意义,因为我完全可以写

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

我希望这两个管道是等效的。显然,他们不是。那么,有什么区别呢?

【问题讨论】:

  • $_ 是 cmdlet 的当前对象,例如 ForEach-Object,例如:'foo', 'bar', 'baz' | ForEach-Object {write-host $_}

标签: powershell pipeline


【解决方案1】:

我希望这两个管道是等效的。

他们不是:

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

它是以下基于管道的等价物(最终效果上的等价物,而非技术上的等价物):

foreach ($str in 'foo', 'bar', 'baz') { Write-Host -Object $str }

也就是说,在您的命令中,Write-Host 接收来自管道的输入,该管道隐式绑定到其-Object 参数对于每个输入对象,凭借参数@ 987654326@ 被声明为通过属性[Parameter(ValueFromPipeline=$true)] 接受管道输入


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

管道处理开始之前,参数 - 在您的情况下为$_ - 绑定到参数first

由于$_ 前面没有参数名称,因此它将位置绑定到-隐含的--Object 参数。

然后,当管道处理开始时,管道参数绑定发现没有管道绑定Write-Host参数可以绑定到,因为唯一的这样的参数,-Object绑定,即通过一个参数 $_

换句话说:您的命令错误地尝试绑定-Object 参数两次不幸的是,错误消息并没有完全说明这一点。

更重要的一点是使用$_ 只在脚本块中才有意义 ({ ... })为每个输入对象评估 /em>.
在该上下文之外,$_(或其别名,$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,而是传递一个 为每个输入对象评估的脚本块 - 绑定输入对象$_,像往常一样 - 启用动态行为。

然而,正如链接答案中所解释的,此技术仅适用于 (a) 管道绑定和 (b) [object][scriptblock] 类型的参数;因此,鉴于Write-Object-Object 参数 [object] 类型化,该技术不起作用

 # Try to enclose all inputs in [...] on output.
 # !! DOES NOT WORK.
 'foo', 'bar', 'baz' | write-host -Object { "[$_]" }

因此,在这种情况下,基于管道的解决方案需要使用ForEach-Object

# -Object is optional
PS> 'foo', 'bar', 'baz' | ForEach-Object { write-host -Object "[$_]" }
[foo]
[bar]
[baz]

【讨论】:

    【解决方案2】:

    您可以按照iRon 在 cmets 中的说明使用它。 $_$PSItem 是管道中正在处理的当前对象。通常,您会在需要处理或脚本块的命令中看到这一点。您必须将您的 Write-Host 命令包含在类似的处理块中。

    'foo', 'bar', 'baz' | ForEach-Object {write-host $_}
    

    这里是一个使用函数的进程块的例子:

    function write-stuff {
        process { write-host $_ }
    }
    
    'foo', 'bar', 'baz' | write-stuff
    bar
    foo
    hi
    

    【讨论】:

      猜你喜欢
      • 2014-08-31
      • 1970-01-01
      • 2012-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-04
      • 2011-08-12
      相关资源
      最近更新 更多