为什么管道不适用于转换后的 json 对象?
Why does the pipeline not work on converted json objects?
考虑以下代码:
$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
.
我们是否遗漏了一些明显的东西?
与:
$data | ConvertFrom-Json | Where-Object { $_.Name -eq 'banana' }
发生以下情况:
ConvertFrom-Json
returns 对象数组(对象本身)。由于这是第一个(最后也是唯一的)“完成”对象 ConvertFrom-Json
return,它作为一个整体传递到管道中。请记住,一个 cmdlet 通常可以 return 多个对象数组。
因此,Where-Object
在这种情况下只接收一个对象(具有三个元素的整个数组)。 $_
然后引用整个数组,而不是每个元素。因此,$_.Name
并不是return一个元素的名称,而是所有元素名称的列表。此外,在这种情况下,术语 $_.Name -eq 'banana'
不是布尔表达式,而是经过过滤的元素名称列表(该列表仅包含 'banana')。只要列表不为空,它就会被 Where-Object
评估为 $true
,因此您的整个数组(一个对象,具有三个元素)将进一步通过管道传输(在您的情况下打印)。所以,它并不是你假设的return三个对象,而是一个对象,包含三个对象。
你的另一行对比:
($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
考虑以下代码:
$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
.
我们是否遗漏了一些明显的东西?
与:
$data | ConvertFrom-Json | Where-Object { $_.Name -eq 'banana' }
发生以下情况:
ConvertFrom-Json
returns 对象数组(对象本身)。由于这是第一个(最后也是唯一的)“完成”对象ConvertFrom-Json
return,它作为一个整体传递到管道中。请记住,一个 cmdlet 通常可以 return 多个对象数组。因此,
Where-Object
在这种情况下只接收一个对象(具有三个元素的整个数组)。$_
然后引用整个数组,而不是每个元素。因此,$_.Name
并不是return一个元素的名称,而是所有元素名称的列表。此外,在这种情况下,术语$_.Name -eq 'banana'
不是布尔表达式,而是经过过滤的元素名称列表(该列表仅包含 'banana')。只要列表不为空,它就会被Where-Object
评估为$true
,因此您的整个数组(一个对象,具有三个元素)将进一步通过管道传输(在您的情况下打印)。所以,它并不是你假设的return三个对象,而是一个对象,包含三个对象。
你的另一行对比:
($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