powershell - 为什么进程 block 正确返回哈希表,而不是哈希表数组?

标签 powershell hashtable powershell-7.0 powershell-7.2

我正在尝试对一些 REST API 响应进行排序并从中提取数据,结果发现 this helpful回答如何在最后得到一个哈希表。

$res= (Invoke-RestMethod @commonParams -uri "foo" -Method GET -FollowRelLink) | ForEach-Object { $_ } | Select-Object -Property id, filename | ForEach-Object -begin {$h=@{}} -process {$h[$_.filename] = $_.id} -end {$h}

太好了,所以我想通过去掉开始/过程/结束 block 来缩短它,如下所示:

$res = (Invoke-RestMethod @commonParams -uri "foo" -Method GET -FollowRelLink) | ForEach-Object { $_ } | Select-Object -Property id, filename | ForEach-Object { $h=@{}; $h[$_.filename] = $_.id; $h }

一切都好,我现在应该能够使用方括号通过其键值引用每个项目,但这不起作用,只能通过点表示法引用。

所以我去搜索并找到了this answer ,事实证明这是正确的:

$res.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

但是,即使从通用哈希表构造函数更改为使用 .Add() 方法也没有帮助:

$res = (Invoke-RestMethod @commonParams -uri "foo" -Method GET -FollowRelLink) | ForEach-Object { $_ } | Select-Object -Property id, filename | ForEach-Object { $h=@{}; $h.add($_.filename, $_.id); $h }

$res.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

我将流程 block 添加回:

$res = (Invoke-RestMethod @commonParams -uri "$foo" -Method GET -FollowRelLink) | ForEach-Object { $_ } | Select-Object -Property id, filename | ForEach-Object -begin {$h=@{}} -process {$h[$_.filename] = $_.id} -end {$h}

$res.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object

一切都按预期进行。

所以我想知道,如果可能的话,当我使用进程 block 而不是在管道中创建“假”多行函数时到底发生了什么?

如果有人关心的话,我实际上最终通过使用 here 中的 Group-Object 完全避免了上述问题。 .

最佳答案

ForEach-Object模拟如何script blocks工作于pipeline 。第一个和最后一个片段按预期工作并返回哈希表的原因是 -Begin-End 而不是因为 -Process 执行默认情况下,并且是强制参数。如果您不使用 -Begin,您只需为每个输入对象创建并输出一个新的哈希表。

  • 使用ForEach-Object
0..10 | ForEach-Object -Begin {
    "executes only once, before the first input object is processed"
} -Process {
    "processes each input object: $_"
} -End {
    "executes only once, after the last input object is processed"
}
  • 使用脚本 block
0..10 | & {
    begin {
        "executes only once, before the first input object is processed"
    }
    process {
        "processes each input object: $_"
    }
    end {
        "executes only once, after the last input object is processed"
    }
}

about_Functions_Advanced_Methods解释这些 block 是如何工作的。

您的代码也可以简化为:

$h = @{}
Invoke-RestMethod @commonParams -uri "foo" -Method GET -FollowRelLink |
    Write-Output |
    ForEach-Object { $h[$_.filename] = $_.id }

或者使用Group-Object -AsHashTable正如您已经发现的:

$h = Invoke-RestMethod @commonParams -uri "foo" -Method GET -FollowRelLink |
    Write-Output |
    Group-Object FileName -AsHashTable
如果已经枚举了 Invoke-RestMethod 的输出,则在这种情况下可能不需要

Write-Output

关于powershell - 为什么进程 block 正确返回哈希表,而不是哈希表数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75467328/

相关文章:

powershell - 如何在PowerShell中将字符串转换为double?

java - 在 Entry<K, V> 类中使用 recordAccess(this)

powershell - 为什么 pwsh.exe 结合 Start-Process 不直接接受脚本 block ?

powershell - PowerShell远程处理:控制目标版本(PowerShell Core或Windows PowerShell);跨平台远程处理的状态

powershell - 如何将默认凭据传递给 PowerShell Web 客户端对象? PS v2 的 Invoke-WebRequest 的替代方案?

floating-point - 散列浮点向量的好方法?

c# - 在 PowerShell 中提供 C# 抽象类的实现

powershell - PowerShell “$g = $json | ConvertFrom-Json | Group State”结果与 “$g = $json | ConvertFrom-Json ; $g = $g | Group State ;”不同

algorithm - 三叉树与哈希表