为什么我不能在写主机中使用 $_?
Why can't I use $_ in write-host?
我正在尝试将字符串数组通过管道传输到 write-host 并明确使用 $_
来写入这些字符串:
'foo', 'bar', 'baz' | write-host $_
然而,它失败了:
The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
这条错误消息对我来说毫无意义,因为我完全可以写
'foo', 'bar', 'baz' | write-host
我原以为两条管道是等价的。显然,他们不是。那么,有什么区别呢?
您可以按照 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
I would have expected both pipelines to be equivalent.
他们不是:
'foo', 'bar', 'baz' | write-host
它是以下基于管道的等效项(最终效果等效,技术上不等效):
foreach ($str in 'foo', 'bar', 'baz') { Write-Host -Object $str }
也就是说,在您的命令中,Write-Host
从管道接收输入, 隐式地 绑定到它的 -Object
参数 每个输入对象 ,由于参数 -Object
被声明为通过属性 [Parameter(ValueFromPipeline=$true)]
接受管道输入
'foo', 'bar', 'baz' | write-host $_
在 管道处理开始之前,参数 - $_
在你的例子中 - 绑定到参数 首先:
由于 $_
前面没有参数名称,因此它将 按位置 绑定到 - 隐含 - -Object
参数。
然后,当流水线处理开始时,流水线 参数绑定发现没有流水线绑定 Write-Host
参数再绑定到,假设只有这样的参数,-Object
已经被绑定,即被参数 $_
.
换句话说:您的命令错误地尝试绑定 -Object
参数 两次 ; 不幸的是,错误消息没有准确地说清楚。
更重要的一点是,使用 $_
只有在脚本块内 才有意义 ({ ... }
) 为每个输入对象计算。
在该上下文之外,$_
(或其别名 $PSItem
)通常没有任何价值,不应使用。
虽然 $_
最常用于传递给 ForEach-Object
和 Where-Object
cmdlet 的脚本块,但还有其他有用的应用程序,最常见的是 Rename-Item
cmdlet:一个 :
# 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) not [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]
我正在尝试将字符串数组通过管道传输到 write-host 并明确使用 $_
来写入这些字符串:
'foo', 'bar', 'baz' | write-host $_
然而,它失败了:
The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
这条错误消息对我来说毫无意义,因为我完全可以写
'foo', 'bar', 'baz' | write-host
我原以为两条管道是等价的。显然,他们不是。那么,有什么区别呢?
您可以按照 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
I would have expected both pipelines to be equivalent.
他们不是:
'foo', 'bar', 'baz' | write-host
它是以下基于管道的等效项(最终效果等效,技术上不等效):
foreach ($str in 'foo', 'bar', 'baz') { Write-Host -Object $str }
也就是说,在您的命令中,Write-Host
从管道接收输入, 隐式地 绑定到它的 -Object
参数 每个输入对象 ,由于参数 -Object
被声明为通过属性 [Parameter(ValueFromPipeline=$true)]
'foo', 'bar', 'baz' | write-host $_
在 管道处理开始之前,参数 - $_
在你的例子中 - 绑定到参数 首先:
由于 $_
前面没有参数名称,因此它将 按位置 绑定到 - 隐含 - -Object
参数。
然后,当流水线处理开始时,流水线 参数绑定发现没有流水线绑定 Write-Host
参数再绑定到,假设只有这样的参数,-Object
已经被绑定,即被参数 $_
.
换句话说:您的命令错误地尝试绑定 -Object
参数 两次 ; 不幸的是,错误消息没有准确地说清楚。
更重要的一点是,使用 $_
只有在脚本块内 才有意义 ({ ... }
) 为每个输入对象计算。
在该上下文之外,$_
(或其别名 $PSItem
)通常没有任何价值,不应使用。
虽然 $_
最常用于传递给 ForEach-Object
和 Where-Object
cmdlet 的脚本块,但还有其他有用的应用程序,最常见的是 Rename-Item
cmdlet:一个
# 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) not [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]