gpt4 book ai didi

powershell - 开始/处理/结束如何节省对foreach的需求?还需要该参数吗?

转载 作者:行者123 更新时间:2023-12-03 14:07:46 25 4
gpt4 key购买 nike

我已经了解到,对于管道中的每个对象,开始/处理/结束处理部分将运行多次。因此,如果我有这样的功能:

function Test-BeginProcessEnd {
[cmdletbinding()]
Param(
[Parameter(Mandatory=$true, ValueFromPipeline=$True)]
[string]$myName
)
begin {}
process {
Write-Host $myName
}
end {}
}

我可以像这样将数组传递给它,然后它处理每个对象:
PS C:\> @('aaa','bbb') | Test-BeginProcessEnd
aaa
bbb
PS C:\>

但是,如果尝试在命令行中使用参数,则只能将其传递1个字符串,因此可以执行以下操作:
PS C:\> Test-BeginProcessEnd -myName 'aaa'
aaa
PS C:\>

但是我不能:
PS C:\> Test-BeginProcessEnd -myName @('aaa','bbb')
Test-BeginProcessEnd : Cannot process argument transformation on parameter 'myName'. Cannot convert value to type
System.String.
At line:1 char:30
+ Test-BeginProcessEnd -myName @('aaa','bbb')
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Test-BeginProcessEnd], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Test-BeginProcessEnd
PS C:\>

显然,我希望参数用法与通过管道相同,因此我必须将函数更改为:
function Test-BeginProcessEnd
{
[cmdletbinding()]
Param(
[Parameter(Mandatory=$true, ValueFromPipeline=$True)]
[string[]]$myNames
)
begin {}
process {
foreach ($name in $myNames) {
Write-Host $name
}
}
end {}
}

因此,无论如何,我都不得不使用foreach,而Process部分的循环功能并没有帮助我。

我错过了什么吗?我看不出有什么好处!谢谢你的帮助。

最佳答案

tl;博士:

由于在PowerShell中将管道输入绑定(bind)到参数是如何工作的(请参见下文),定义了一个参数,该参数接受管道输入以及数组的直接参数值传递:

  • 实际上需要在process块内循环
  • 总是将通过管道接收的各个输入对象包装在每个的单元素数组中,这效率很低。

  • 将流水线绑定(bind)参数定义为标量可以避免这种笨拙的,但是传递多个输入的 限于流水线-您将无法将数组作为参数参数传递。[1]

    这种不对称可能令人惊讶。

    当定义一个接受管道输入的参数时,您将免费获得隐式数组逻辑:
  • 使用管道输入,PowerShell为每个输入对象调用一次process块,当前输入对象绑定(bind)到参数变量。
  • 相比之下,将输入作为参数值传递仅一次输入process,而输入作为整体绑定(bind)到参数变量。

  • 无论您的参数是否为数组值,以上内容均适用:每个管道输入对象都严格按照声明的方式绑定(bind)/强制为参数的类型。

    具体来说,您可以使用示例函数来声明参数 [Parameter(Mandatory=$true, ValueFromPipeline=$True)] [string[]] $myNames:

    让我们假设 'foo', 'bar'的输入数组(集合)(请注意,通常不需要数组文字周围的 @())。
  • 参数值输入Test-BeginProcessEnd -myNames 'foo', 'bar':
  • process块被调用一次,
  • 整个输入数组 'foo', 'bar'绑定(bind)到 $myNames
  • 管道输入,'foo', 'bar' | Test-BeginProcessEnd:
  • process块被调用两次,
  • 带有 'foo''bar'
  • 都被强制转换为[string[]]-即单元素数组。

  • 要查看实际效果:
    function Test-BeginProcessEnd
    {
    [cmdletbinding()]
    Param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [string[]]$myNames
    )
    begin {}
    process {
    Write-Verbose -Verbose "in process block: `$myNames element count: $($myNames.Count)"
    foreach ($name in $myNames) { $name }
    }
    end {}
    }
    # Input via parameter
    > Test-BeginProcessEnd 'foo', 'bar'
    VERBOSE: in process block: $myNames element count: 2
    foo
    bar

    # Input via pipeline
    > 'foo', 'bar' | Test-BeginProcessEnd
    VERBOSE: in process block: $myNames element count: 1
    foo
    VERBOSE: in process block: $myNames element count: 1
    bar

    可选阅读:各种提示功能和管道输入
  • beginprocessend块可以在函数中使用,无论它是否是高级函数(类似于cmdlet的功能,请参见下文)。
  • 如果只需要管道中的第1个对象或一定数量的对象,则当前无法过早退出管道;否则,请参见。相反,您必须设置一个 bool(boolean) 值标志,告诉您何时忽略后续的process块调用。
  • 但是,您可以使用一个中间的单独调用,例如| Select-Object -First 1,该调用在收到所需数目的对象之后有效地退出管道。
  • 当前无法通过用户代码执行此操作是this suggestion on GitHub的主题。
  • 另外,您可以放弃process块,并在函数中使用$Input | Select-Object 1,但是,如上所述,它将首先收集内存中的所有输入。在我的this answer中可以找到另一个(也是不完美的)替代方法。
  • 如果不使用这些块,仍然可以选择通过自动$Input变量访问管道输入。但是请注意,函数将在所有管道输入都收集到内存中之后运行(而不是像process块那样逐个对象)。
  • 通常,虽然值得使用process块:
  • 对象可以由source命令生成,因此可以一一处理,这有两个好处:
  • 它使处理效率更高,因为不必首先完整收集源命令的输出。
  • 您的函数立即开始产生输出,而无需等待source命令首先完成。
  • 希望很快(参见上文),一旦所有感兴趣的对象都已处理完,您将能够退出管道。
  • Cleaner语法和结构:process块是所有管道输入上的隐式循环,您可以分别在beginend块中有选择地执行初始化和清理任务。
  • 很容易将函数转换为advanced function,但是,这在支持common parameters(例如-ErrorAction-OutVariable)以及检测无法识别的参数方面具有很多优势:
  • 使用param()块来声明参数并用[CmdletBinding()]属性装饰该块,如上所示(同样,用[Parameter()]属性装饰单个参数会使函数隐式地成为高级功能,但为清楚起见,最好明确使用[CmdletBinding()]) 。


  • [1]严格来说,可以,但是只有在键入参数 [object]时(或者根本不指定类型,这是相同的)。
    但是,然后将输入数组/集合作为一个整体绑定(bind)到参数变量,并且 process块仍只输入一次,您需要在其中执行自己的枚举。
    一些标准的cmdlet(例如 Export-Csv)是通过这种方式定义的,但是它们并未枚举通过 -InputObject参数传递的集合,从而使直接使用该参数实际上没有用-请参阅 this GitHub issue

    关于powershell - 开始/处理/结束如何节省对foreach的需求?还需要该参数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48347560/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com