3

考虑以下代码:

$data = '[
    {
        "Name":  "banana",
        "Color":  "yellow"
    },
    {
        "Name":  "kiwi",
        "Color":  "green"
    },
    {
        "Name":  "apple",
        "Color":  "red"
    }
]'
# Returns 3 objects while only 1 was expected
$data | ConvertFrom-Json | Where-Object { $_.Name -eq 'banana' }

# Workaround, returns 1 object as expected:
($data | ConvertFrom-Json) | Where-Object { $_.Name -eq 'banana' }

为什么不能使用第一个选项?从 json 转换对象后,该Where-Object函数似乎不正确。这发生在 PowerShell 版本上5.1

我们在这里遗漏了一些明显的东西吗?

4

1 回答 1

1

和:

$data | ConvertFrom-Json | Where-Object { $_.Name -eq 'banana' }

会发生以下情况:

  1. ConvertFrom-Json返回一个对象数组(它本身就是一个对象)。由于这是第一个(最终也是唯一的)“完成”对象ConvertFrom-Json返回,因此它作为一个整体传递到管道中。请记住,一个 cmdlet 通常可以返回多个对象数组。

  2. 因此,Where-Object在这种情况下只接收一个对象(包含三个元素的整个数组)。$_然后引用整个数组,而不是每个元素。因此,$_.Name返回的不是一个元素的名称,而是所有元素名称的列表。此外,$_.Name -eq 'banana'在这种情况下,术语不是布尔表达式,而是元素名称的过滤列表(该列表仅包含“香蕉”)。只要列表不为空,它将被评估为$trueby Where-Object,因此您的整个数组(一个对象,具有三个元素)将进一步通过管道传输(在您的情况下打印)。因此,它不会像您假设的那样返回三个对象,而是返回一个包含三个对象的对象。

相比之下,您的另一条线:

($data | ConvertFrom-Json) | Where-Object { $_.Name -eq 'banana' }

好吧,简而言之,做你期望它做的事情。为什么?因为圆括号打破了管道。由于括号,括号内的所有内容都将被完全评估,然后再进一步传输。在评估括号后,会有一个数组,它将被进一步传送。整个数组将逐个元素地通过管道传输。所以在这种情况下,Where-Object接收三个单个对象,就像你预期的那样。


另一个很好的例子是:

您不能覆盖当前正在读取的文件:

Get-Content test.txt | Set-Content test.txt

但是你可以在读完文件后覆盖它:

(Get-Content test.txt) | Set-Content test.txt
于 2021-09-01T07:52:45.840 回答