powershell 为什么我不能在write-host中使用$_?

mitkmikd  于 2023-01-05  发布在  Shell
关注(0)|答案(3)|浏览(142)

我尝试通过管道将字符串数组传输到write-host,并显式使用$_写入这些字符串:

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

但是,它失败的原因是:

  • 无法将输入对象绑定到命令的任何参数,因为命令不接受管道输入,或者输入及其属性与接受管道输入的任何参数都不匹配。*

这个错误消息对我来说毫无意义,因为我完全能够编写

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

我本以为这两条管道是等效的。显然,它们不是。那么,有什么区别呢?

kh212irz

kh212irz1#

左,右

      • 自动$_变量及其 * 别名 * $PSItem仅在特定上下文中 * 在脚本块 *({ ... })**内具有有意义的值。
  • 底部列出了所有相关上下文。
    • 更新 *:现在提供了一个新的概念性帮助主题about_PSItem,它涵盖了底部部分的大部分内容。

我本以为两条管线是等效的。
他们不是:
'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 $_

  • 在 * 管道处理开始之前,* arguments *(在您的示例中为$_)绑定到参数 * first *:

因为$_前面没有参数名,所以它在 * 位置上 * 绑定到-implied--Object参数。
然后,当流水线处理开始时,* 流水线 * 参数绑定发现没有流水线绑定Write-Host参数要再绑定到,假定唯一这样的参数-Object * 已经被绑定 ,即通过 * 自变量 * $_
换句话说:
* 命令错误地尝试绑定-Object参数 * 两次 *; * * 不幸的是,错误消息并没有明确说明这一点。
更重要的一点是,**使用$_只在脚本块 *({ ... })**内有意义,该脚本块 *({ ... })**为每个输入对象 * 计算 *。
在该上下文之外,$_(或其别名$PSItem)通常没有值,不应使用-请参阅底部部分以了解所有上下文的概述,在这些上下文中,脚本块中的$_/$PSItem得到了有意义的支持。
虽然$_最常用于传递给ForEach-ObjectWhere-Object cmdlet的脚本块中,但还有其他有用的应用程序,最常使用Rename-Item cmdlet:a delay-bind script-block argument

# Example: rename *.txt files to *.dat files using a delay-bind script block:
Get-ChildItem *.txt | Rename-Item -NewName { $_.BaseName + '.dat' } -WhatIf

也就是说,不是向Rename-Item传递一个 * static * 新名称,而是传递一个 * script块,该块针对每个输入对象 * 进行求值(输入对象通常绑定到$_),从而启用动态行为。
然而,如链接答案中所解释的,该技术仅对(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]
有意义地定义$_(及其别名$PSItem)的上下文:

这些上下文的共同之处在于,$_/$PSItem引用必须在script block{ ... }内进行,也就是说,一个传递给*/在中使用:

1..3 | ForEach-Object { 1 + $_ } # -> 2, 3, 4
  • 内部.ForEach()和内部.Where()方法;例如:
(1..3).ForEach({ 1 + $_ }) # -> 2, 3, 4
  • 参数,假设该参数允许脚本块充当延迟绑定脚本块参数;例如:
# Rename all *.txt files to *.dat files.
Get-ChildItem *.txt | Rename-Item -NewName { $_.BaseName + '.dat' } -WhatIf
  • ... switch语句中的条件和相关脚本块;例如:
# -> 'is one or three: one', 'is one or three: three'
switch ('one', 'two', 'three') {
  { $_ -in 'one', 'three' } { 'is one or three: ' + $_ }
}
  • ...简单的functionfilters;例如:
# -> 2, 3
function Add-One { process { 1 + $_ } }; 1..2 | Add-One

# -> 2, 3
filter Add-One { 1 + $_ }; 1..2 | Add-One
  • ...直接订阅对象的事件(不适用于传递给Register-ObjectEvent调用的-Action参数的脚本块);例如::对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.
})
  • ...参数声明中的[ValidateScript()]属性;注意,对于 * array * 值参数,脚本块被称为 * for each element *;例如,
function Get-Foo {
  param(
    [ValidateScript({ 0 -eq ($_ % 2) })]
    [int[]] $Number
  )
  "All numbers are even: $Number"
}
# -> 'a10, 'a20'
'a1', 'a2' -replace '\d+', { 10 * [int] $_.Value }
  • ...在formatting files中的<ScriptBlock>元素的上下文中(但在基于脚本块的ETS成员的上下文中 * 不是 *,其中改用$this)。
  • ...在使用.InvokeWithContext()等 * PowerShell SDK方法 * 的上下文中
# -> 43
{ 1 + $_ }.InvokeWithContext($null, [psvariable]::new('_', 42), $null)
eoxn13cs

eoxn13cs2#

您可以像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
waxmsbnn

waxmsbnn3#

$_在脚本块之外 * 永远 * 不会工作。用write-output代替怎么样:

'hi' | Write-Output -InputObject { $_ + ' there' } 

hi there

相关问题