如何解决为什么需要将ConvertFrom-Json用圆括号传递到Foreach-Object?
我有这个功能来获取json文件的内容。
我有一些(对我而言)意外的行为,试图将其通过管道传递到ConvertTo-Json
和Foreach-Object
Function GetConfigJson
{
$ConfigPath = "pathtomyjsonfile.json"
return Get-Content $ConfigPath | Out-String
}
json的格式类似于[{"key1":"value1"},{"key2":"value2"},...]
要测试行为,我做了以下事情:
$a = 0;
GetConfigJson | ConvertFrom-Json | ForEach-Object { $a++ };
$b = 0;
ConvertFrom-Json GetConfigJson | ForEach-Object { $b++ };
$c = 0;
ConvertFrom-Json (GetConfigJson) | ForEach-Object { $c++ };
$d = 0;
(ConvertFrom-Json (GetConfigJson)) | ForEach-Object { $d++ };
Write-Host "Test1: $a | Test2: $b | Test3: $c | Test4: $d";
仅在这些Test4
中打印期望的数字,Test1
和Test3
打印1
,而Test2
则出错:ConvertFrom-Json : Invalid JSON primitive: GetConfigJson.
/ p>
为什么我需要在ConvertFrom-Json周围加上括号才能将其作为对象数组进行管道传递?
(更容易接受函数名GetConfigJson
的括号-但我仍然想知道为什么在那里需要它?)
解决方法
研究每个示例的输出类型可能会有所帮助-参见下面的细分。
助手功能
我在下面的小节中使用这两个辅助函数。注意-我猜您的配置在根目录处有一个数组,因为这似乎可以重现该问题,但是如果不正确,请随时更新您的问题。
ssh remoteHost 'find pathToRemoteDir -mtime -2 -type f -printf "%f\0"' |
rsync -av --from0 --files-from=- remoteHost:pathToRemoteDir .
然后使用您的示例:
示例1
function GetConfigJson
{
return "[{""name"":""first""},{""name"":""second""}]"
}
function Write-Value
{
param( $Value )
write-host $Value.GetType().FullName
write-host (ConvertTo-Json $Value -Compress)
}
# example 1a - original example
PS> $a = 0
PS> GetConfigJson | ConvertFrom-Json | ForEach-Object { $a++ };
PS> $a
1
# example 1b - show return types and values
PS> GetConfigJson | ConvertFrom-Json | foreach-object { Write-Value $_ }
System.Object[]
{"value":[{"name":"first"},{"name":"second"}],"Count":2}
返回具有两个条目的数组对象,但是ConvertFrom-Json
仅运行一次,因为它遍历单个数组 object ,而不是2个 items 。
示例2
Foreach-Object
# example 2a - original example
PS> $b = 0;
PS> ConvertFrom-Json GetConfigJson | foreach-object { $b++ }
ConvertFrom-Json : Invalid JSON primitive: GetConfigJson.
At line:1 char:1
+ ConvertFrom-Json GetConfigJson | foreach-object { $b++ }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ConvertFrom-Json],ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
# example 2b - show parameter types and values
PS> Write-Value GetConfigJson
System.String
"GetConfigJson"
引发异常,因为PowerShell将ConvertFrom-Json
当作文字字符串,但是GetConfigJson
显然不是有效的json,因此是异常。
示例3
"GetConfigJson"
这在# example 3a - original example
PS> $c = 0;
PS> ConvertFrom-Json (GetConfigJson) | ForEach-Object { $c++ };
PS> $c
1
# example 3b - show parameter types and values
PS> ConvertFrom-Json (GetConfigJson) | ForEach-Object { Write-Value $_ };
System.Object[]
{"value":[{"name":"first"},"Count":2}
周围使用Grouping Operator ( ... )
,因此PowerShell将GetConfigJson
评估为对函数的调用,而不是将其视为文字字符串。它首先执行GetConfigJson
表达式,然后将其结果作为参数传递给GetConfigJson
。但是,它仍然在单个数组对象而不是项目上进行迭代,因此ConvertFrom-Json
仅运行一次。
示例4
foreach-object
我们在这里使用分组运算符两次-一次在# example 4a - original example
PS> $d = 0;
PS> (ConvertFrom-Json (GetConfigJson)) | ForEach-Object { $d++ };
PS> $d
2
# example 4b - show parameter types and values
PS> (ConvertFrom-Json (GetConfigJson)) | ForEach-Object { Write-Value $_ };
System.Management.Automation.PSCustomObject
{"name":"first"}
System.Management.Automation.PSCustomObject
{"name":"second"}
周围将其评估为表达式,而不是字符串,一次在整个GetConfigJson
周围。外部ConvertFrom-Json (GetConfigJson)
使PowerShell可以“展开”单个数组对象,并将其 items 释放到( ... )
消耗的管道中。这意味着Foreach-object
在 items 上进行迭代,我们看到了两个单独的值,分别由“ Write-Value”`
摘要
您设法解决了许多PowerShell怪癖问题-希望此答案有助于您理解它们的全部工作以及为什么您会看到自己的行为。
PowerShell 7的更新
根据下面@ mklement0中的注释,ForEach-Object
的行为从版本7开始发生变化-默认情况下它不会枚举数组,并且要求ConvertFrom-Json
退出。
例如,-NoEnumerate
现在在v7 +中报告2,而'[ 1,2 ]' | ConvertFrom-Json | Measure-Object
是获得v6行为所必需的:-NoEnumerate
(报告1)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。