gpt4 book ai didi

PowerShell ForEach-Object 消除

转载 作者:行者123 更新时间:2023-12-02 23:50:35 26 4
gpt4 key购买 nike

让我们考虑一个集合的集合,以及需要在管道内对内部集合的每个元素执行的操作。

为了简单起见,让它成为一个数组数组,操作简单的打印到屏幕上。为了表达我的问题,让我们还有一个元素不是集合的数组:

$Array = "A", "B", "C"
$ArrayOfArrays = (1, 2, 3), (4, 5, 6), (7, 8, 9)

我们知道管道会将集合分解为元素,如下所示:
$Array | & {process {Write-Host $_}}
$ArrayOfArrays | & {process {Write-Host $_}}

现在,令我惊讶的是,当我运行它时,它并没有将内部数组分解为它的元素:
$ArrayOfArrays | % -process {Write-Host $_} (1)

这也不是:
$ArrayOfArrays | % -process {% -process {Write-Host $_}} (2)

(但是后者似乎是不必要的尝试,看到 (1) 没有这样做,但我尝试过......)
我希望尝试 (1) 这样做,因为我认为管道会发生故障,并且当 ForEach-Object 接收到元素时,如果它是一个集合,它将进一步分解它。

我只能用内部管道解决它:
$ArrayOfArrays | % -process {$_ | % -process {Write-Host $_}} (3)

但是通过这种方法,我可以消除 ForEach-Object , 当然:
$ArrayOfArrays | & {process {$_ | & {process {Write-Host $_}}}} (4)

所以我的两个问题是:

1 ,

How to access an element of a collection that is in the collection in a pipeline, other than tries (3) and (4), or is this the only way to do that?



2 ,

If the only way to do what question 1 is asking is tries (3) and (4), then what is a valid use case of ForEach-Object, where it can not be eliminated? I mean it can be a logical case, but also performance vs a script block. The fact that it is nicer than a script block with one pair of braces less is just not really enough for me...



.
在 Manuel Batsching 回答后编辑:

作为 ForEach-Object处理后返回一个集合的元素,我们可以这样做(我放开了Write-Host,可能不是很好的任意操作,所以让它成为GetType):
$ArrayOfArrays | % -process {$_} | & {process {$_.GetType()}}

但是我们也知道,如果某个东西在管道中返回了一个新对象,如果它被进一步管道化并且它是一个集合,它将触发故障。所以要进行分割,我们可以再次消除 ForEach-Object并这样做:
$ArrayOfArrays | & {process {$_}} | & {process {$_.GetType()}}

如果我定义这样的过滤器,则可以在语法上减少这个虚拟操作:
Filter §
{
param (
[Parameter (Mandatory = $True, ValueFromPipeline = $True)]
[Object]
$ToBeTriggeredForBreakDown
) # end param

$ToBeTriggeredForBreakDown

}

并像这样使用它:
$Array | § | & {process {$_.GetType()}}
$ArrayOfArrays | § | & {process {$_.GetType()}}

$ArrayOfArraysOfArrays = ((1, 2), (3, 4)), ((5, 6), (7, 8))
$ArrayOfArraysOfArrays | § | & {process {$_.GetType()}}
$ArrayOfArraysOfArrays | § | § | & {process {$_.GetType()}}

所以我仍然很难看到我何时会使用 ForEach-Object ,在我看来这完全没用——除了我在问题中寻找的原因。

.
研究后编辑:

一些集合提供了自己的方法,例如从 v4 arrays有一个 ForEach方法,因此除了 (3) 和 (4) 之外,还可以执行此操作(同样是一个虚拟操作,但代码较少):
$ArrayOfArrays.ForEach{$_} | & {process {$_.GetType()}}

所以这部分涵盖了问题1。

最佳答案

在我的理解中,一旦数组被传递到管道或输出流,数组的解包就完成了。

您将通过以下所有方法看到这种行为:

$ArrayOfArrays | % -process { $_ }
$ArrayOfArrays | & { process { $_ } }
foreach ($arr in $ArrayOfArrays) { $arr }

现在,在您的示例中破坏展开的是 Write-Host cmdlet。由于此 cmdlet 不是写入输出流而是写入您的控制台,因此它将输入对象转换为 [string] .这就是为什么您会在控制台上看到内部数组的字符串表示。

替换 Write-HostWrite-Output并且内部数组将被正确展开:
 PS> $ArrayOfArrays | % -process { Write-Output $_ }
1
2
3
4
5
6
7
8
9

编辑:

您可以使用调试器来准确确定展开的位置。例如,在 VSCode 中使用以下代码:
$ArrayOfArrays = (1, 2, 3), (4, 5, 6), (7, 8, 9)
$foo = $null
$foo = $ArrayOfArrays | % { Write-Output $_ }

将断点设置到行 $foo = $null ,添加变量 $foo$_到监视列表,按 F5 启动调试器并观察变量变化,同时按 F11 进入各个处理步骤。
  • $_将显示内部数组,它是管道中的当前元素。
  • $foo管道执行结束后将只接收未包装的元素
  • 关于PowerShell ForEach-Object 消除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60297091/

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