powershell - 为什么我不能在 write-host 中使用 $_?
问题描述
我正在尝试将字符串数组通过管道传输到 write-host 并显式用于$_
写入这些字符串:
'foo', 'bar', 'baz' | write-host $_
但是,它失败了:
输入对象不能绑定到命令的任何参数,因为命令不接受管道输入,或者输入及其属性与接受管道输入的任何参数都不匹配。
这个错误信息对我来说毫无意义,因为我完全可以写
'foo', 'bar', 'baz' | write-host
我本来希望两个管道是等效的。显然,他们不是。那么,有什么区别呢?
解决方案
我本来希望两个管道是等效的。
他们不是:
'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
参数两次;不幸的是,错误消息并没有完全说明这一点。
更重要的一点是,仅在为每个输入对象评估的脚本块( )中使用$_
ever 才有意义{ ... }
。
在该上下文之外,(或其别名,)通常没有价值,不应使用。$_
$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' }
也就是说,不是将静态新名称传递给 ,而是Rename-Item
传递一个为每个输入对象评估的脚本块- 输入对象绑定到$_
,像往常一样 - 启用动态行为。
然而,正如链接答案中所解释的那样,这种技术仅适用于(a)管道绑定和(b)不是 [object]
或[scriptblock]
类型的参数;因此,如果输入了Write-Object
's-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]
推荐阅读
- android - 当试图让 ViewBinding 工作时,为什么我的一些布局文件需要以
而其他人没有? - python - 在“诗歌构建”上执行自定义功能
- c# - 如何让我的组合框停止自动更改值
- flutter - Flutter:在 SliverPersistentHeader 的“成形”区域中显示 SliverList
- testing - 如何使用不同的配置进行测试与部署安全帽可靠性?
- jenkins - 如何修复 Jenkins 的 yum 更新
- json - 特定位置的 JSON 值的术语(属性?)
- arrays - 只提取谷歌表格中每个单元格的第一行
- php - 将 cUrl 连接到 api:不能将响应用作 JSON
- javascript - JavaScript 检查对象是否存在于数组中