我正在查看PowerShell的Rename-Item cmdlet的文档,并且有一个这样的示例。

Get-ChildItem *.txt | Rename-Item -NewName { $_.name -Replace '\.txt','.log' }

注意最后一句话:
NewName的值是一个脚本块,在将值提交给NewName参数之前运行。
实际上NewName是一个字符串:
[-NewName] <String>
那么这是否意味着当所需的参数类型为字符串时,我总是可以使用脚本块吗?

最佳答案

# Delay-bind script-block argument:
# The code inside { ... } is executed for each input object ($_) and
# the output is passed to the -NewName parameter.
... | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }
上面的调用显示了延迟绑定(bind)脚本块({ ... })参数的应用,该参数是隐式功能,它具有:
  • 仅适用于旨在接受管道输入的参数,

  • 除了以下以外的任何类型,在这种情况下都会进行常规参数绑定(bind)[1]:
  • [scriptblock]
  • [object](但是[psobject]确实起作用,因此也适用[pscustomobject])
  • (未指定类型),实际上与[object]
  • 相同

  • 此类参数是否接受按值(ValueFromPipelineBy)或按属性名(ValueFromPipelineByPropertyName)接受管道输入都是无关紧要的。

  • 通过传递的脚本块而不是类型合适的参数来启用按输入对象的转换;将为每个管道对象评估脚本块,该脚本块通常可以通过$_在脚本块内部进行访问,并且脚本块的输出(假定为参数的类型正确)用作参数。
  • 由于定义上的此类即席脚本块与您要定位的参数类型不匹配,因此在传递它们时必须始终使用参数名称
  • 延迟绑定(bind)脚本块无条件提供对管道输入对象的访问,即使该参数通常不被给定的管道对象绑定(bind),即使它被定义为ValueFromPipelineByPropertyName并且该对象缺少该名称的属性也是如此。
  • 这将启用诸如以下对Rename-Item的调用之类的技术,其中Get-Item的管道输入(通常)绑定(bind)到-LiteralPath参数,但是将脚本块传递给-NewName-通常只绑定(bind)到具有.NewName属性的输入对象-启用对同一管道对象的访问,从而从输入文件名派生目标文件名:
  • Get-Item file | Rename-Item -NewName { $_.Name + '1' } # renames 'file' to 'file1';输入同时绑定(bind)到-LiteralPath-NewName脚本块。

  • 注意:例如,与传递给ForEach-ObjectWhere-Object的脚本块不同, delay-bind脚本块在子变量范围 [2]中运行,这意味着您无法直接修改调用者的变量,例如在输入中增加计数器对象。
    解决方法是,使用在调用方作用域中声明的[ref]类型的变量,并在脚本块中访问其.Value属性-有关示例,请参见this answer


  • [1]错误条件:
  • 如果您错误地尝试将脚本块传递给非管道绑定(bind)或[scriptblock]-或[object]类型(无类型)的参数,则会发生常规参数绑定(bind):
  • (如果有的话)在开始管道输入处理之前,将脚本块传递一次。
    即,脚本块作为(可能是转换的)值传递,并且不进行评估。
  • 对于[object][scriptblock]类型的参数/可转换为脚本块的委托(delegate)类型(例如System.Func),脚本块将按原样绑定(bind)。
  • 对于(非管道绑定(bind))[string]类型的参数,脚本块的文字内容作为字符串值传递。
  • 对于所有其他类型,由于无法从脚本块进行转换,因此参数绑定(bind)(因此整个命令)将仅失败。


  • 如果您在将延迟绑定(bind)脚本块传递给确实支持它们的管道绑定(bind)参数时忽略了提供管道输入,则会收到以下错误:
  • Cannot evaluate parameter '<name>' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input.


  • [2]这个差异正在this GitHub issue中讨论。

    关于powershell - 对于PowerShell cmdlet,是否可以始终将脚本块传递给字符串参数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52805820/

    10-11 08:42