Ren*_*ger 5 powershell pipeline automatic-variable
我正在尝试将字符串数组通过管道传输到 write-host 并显式用于$_写入这些字符串:
'foo', 'bar', 'baz' | write-host $_
Run Code Online (Sandbox Code Playgroud)
但是,它失败了:
输入对象无法绑定到命令的任何参数,因为该命令不采用管道输入,或者输入及其属性与采用管道输入的任何参数都不匹配。
这个错误消息对我来说毫无意义,因为我完全能够写
'foo', 'bar', 'baz' | write-host
Run Code Online (Sandbox Code Playgroud)
我本以为两条管道是等效的。显然,他们不是。那么,有什么区别呢?
太长了;博士
底部列出了所有相关上下文。
我本以为两条管道是等效的。
他们不是:
'foo', 'bar', 'baz' | write-host
它是基于管道的等效项(在最终效果上等效,但在技术上不等效):
foreach ($str in 'foo', 'bar', 'baz') { Write-Host -Object $str }
Run Code Online (Sandbox Code Playgroud)
也就是说,在您的命令中,通过Write-Host将参数声明为通过属性接受管道输入,从管道接收-Object输入,该管道隐式绑定到每个输入对象的参数-Object[Parameter(ValueFromPipeline=$true)]
'foo', 'bar', 'baz' | write-host $_
在管道处理开始之前,参数(在您的情况下)首先$_绑定到参数:
由于$_前面没有参数名称,因此它在位置上绑定到 - 隐含 --Object参数。
然后,当管道处理开始时,管道参数绑定找不到可以再绑定的管道绑定Write-Host参数,因为唯一的此类参数-Object 已经被绑定(即通过参数) $_。
换句话说:您的命令错误地尝试绑定-Object参数两次;不幸的是,错误消息并没有完全说明这一点。
更重要的一点是,仅在针对每个输入对象进行评估的脚本块( )内使用$_ever 才有意义{ ... }。
在该上下文之外,(或其别名,)通常没有值,不应使用 -请参阅底部部分,了解所有上下文的概述,其中/在脚本块内得到有意义的支持。$_$PSItem$_$PSItem
虽然$_最常用于传递给ForEach-Object和Where-Objectcmdlet 的脚本块中,但还有其他有用的应用程序,最常见的是Rename-Itemcmdlet:延迟绑定脚本块参数:
# Example: rename *.txt files to *.dat files using a delay-bind script block:
Get-ChildItem *.txt | Rename-Item -NewName { $_.BaseName + '.dat' } -WhatIf
Run Code Online (Sandbox Code Playgroud)
也就是说,您不是将静态新名称传递给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 { "[$_]" }
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下需要使用基于管道的解决方案ForEach-Object:
# -Object is optional
PS> 'foo', 'bar', 'baz' | ForEach-Object { write-host -Object "[$_]" }
[foo]
[bar]
[baz]
Run Code Online (Sandbox Code Playgroud)
$_(及其别名) 被有意义地定义的上下文$PSItem:这些上下文的共同点是/引用必须在脚本块( )内进行$_$PSItem{ ... },即传递给 / 的引用:
...ForEach-Object和Where-Objectcmdlet;例如:
1..3 | ForEach-Object { 1 + $_ } # -> 2, 3, 4
Run Code Online (Sandbox Code Playgroud)
...内在.ForEach()和内在.Where()方法;例如:
(1..3).ForEach({ 1 + $_ }) # -> 2, 3, 4
Run Code Online (Sandbox Code Playgroud)
...一个参数,假设该参数允许脚本块充当延迟绑定脚本块参数;例如:
# Rename all *.txt files to *.dat files.
Get-ChildItem *.txt | Rename-Item -NewName { $_.BaseName + '.dat' } -WhatIf
Run Code Online (Sandbox Code Playgroud)
...语句内的条件和关联的脚本块switch;例如:
# -> 'is one or three: one', 'is one or three: three'
switch ('one', 'two', 'three') {
{ $_ -in 'one', 'three' } { 'is one or three: ' + $_ }
}
Run Code Online (Sandbox Code Playgroud)
...简单function并且filters;例如:
# -> 2, 3
function Add-One { process { 1 + $_ } }; 1..2 | Add-One
# -> 2, 3
filter Add-One { 1 + $_ }; 1..2 | Add-One
Run Code Online (Sandbox Code Playgroud)
...直接订阅对象的事件(不适用传递给调用-Action参数的脚本块Register-ObjectEvent);例如::向Santiago Squarzon致敬。
# In a direct event-subscription script block used in the
# context of WinForms; e.g:
$txtBox.Add_KeyPress({
param($sender, $eventArgs)
# The alternative to the explicitly defined parameters above is:
# $this ... implicitly the same as $sender, i.e. the event-originating object
# $_ / $PSItem ... implicitly the same as $eventArgs, i.e. the event-arguments object.
})
Run Code Online (Sandbox Code Playgroud)
...[ValidateScript()]参数声明中的属性;请注意,对于数组值参数,将为每个元素调用脚本块;例如,
function Get-Foo {
param(
[ValidateScript({ 0 -eq ($_ % 2) })]
[int[]] $Number
)
"All numbers are even: $Number"
}
Run Code Online (Sandbox Code Playgroud)
仅限PowerShell(核心):...运算符的替换操作数-replace;例如:
# -> 'a10, 'a20'
'a1', 'a2' -replace '\d+', { 10 * [int] $_.Value }
Run Code Online (Sandbox Code Playgroud)
...在格式化文件<ScriptBlock>中元素的上下文中(但不在基于脚本块的ETS 成员的上下文中,而是使用 where )。$this
...在使用PowerShell SDK 方法的上下文中,例如.InvokeWithContext()
# -> 43
{ 1 + $_ }.InvokeWithContext($null, [psvariable]::new('_', 42), $null)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2842 次 |
| 最近记录: |