使用 jq/bash 的可变键迭代 JSON 数组的最佳方法
Best way to iterate over JSON array with variable keys with jq/bash
我有一个 JSON 文件,如下所示:
{
"Results": [
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1"
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2"
},
{
"Severity": "HIGH",
"VulnerabilityID": "CVE-2016-2781"
}
]
}
我想创建以下 JSON-file:
[
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1",
"VulnerabilityID": ""
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "",
"VulnerabilityID": ""
},
{
"Severity": "HIGH",
"InstalledVersion": "",
"FixedVersion": "",
"VulnerabilityID": "CVE-2016-2781"
}
]
我尝试遍历第一个 JSON-文件,但是当我按照以下方式这样做时,我遇到随机解析错误(使用我正在处理的真实 JSON-文件).所以我认为我正在做的管道有问题。
jq -c '.Results[]' my.json | while read i; do
echo $i;
done
在 JSON 文件中,我正在使用 jq -c '.Results[]' 完美运行,但是当我使用 jq 对结果 $i 的操作在迭代时,我突然遇到几个解析错误。
是否有更好的方法来遍历 JSON 文件中的键值对? Ofcause 我可以只安装 Python/R 并进行典型的练习,但我真的希望它能在 shell 脚本中工作。
您可以使用 +
通过组合字段将两个对象相加;如果两个对象具有相同的对象,则使用右手对象的值。因此,如果您将现有对象设为 RHS:
jq '[ .Results[] | {Severity:"", InstalledVersion:"", FixedVersion:"", VulnerabilityID:""} + . ]' input.json
[
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1",
"VulnerabilityID": ""
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "",
"VulnerabilityID": ""
},
{
"Severity": "HIGH",
"InstalledVersion": "",
"FixedVersion": "",
"VulnerabilityID": "CVE-2016-2781"
}
]
另一种将回退添加到空字符串的方法:
[ .Results[] | . + { VulnerabilityID: (.VulnerabilityID // ""), FixedVersion: (.FixedVersion // ""), InstalledVersion: (.InstalledVersion // "") } ]
[
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1",
"VulnerabilityID": ""
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"VulnerabilityID": "",
"FixedVersion": ""
},
{
"Severity": "HIGH",
"VulnerabilityID": "CVE-2016-2781",
"FixedVersion": "",
"InstalledVersion": ""
}
]
Online demo
还有一个变化
jq '[
.Results[]
| .FixedVersion //= ""
| .VulnerabilityID //= ""
| .InstalledVersion //= ""
]' file.json
更通用的方法:
jq '.Results |
(map(keys)|add|unique|map({key:.,value:""})|from_entries) as $default |
map($default + .)
' input.json
解释:
1) map(keys)|add|unique
gets all the keys. If it's a subset you are interested, you can substitute it with :
["FixedVersion", "VulnerabilityID", "InstalledVersion"]
2) map({key:.,value:""})|from_entries) as $default
constructs a default object with all (or selected) keys.
3) $default + .
adds a key from default object if the key does not exist.
我有一个 JSON 文件,如下所示:
{
"Results": [
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1"
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2"
},
{
"Severity": "HIGH",
"VulnerabilityID": "CVE-2016-2781"
}
]
}
我想创建以下 JSON-file:
[
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1",
"VulnerabilityID": ""
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "",
"VulnerabilityID": ""
},
{
"Severity": "HIGH",
"InstalledVersion": "",
"FixedVersion": "",
"VulnerabilityID": "CVE-2016-2781"
}
]
我尝试遍历第一个 JSON-文件,但是当我按照以下方式这样做时,我遇到随机解析错误(使用我正在处理的真实 JSON-文件).所以我认为我正在做的管道有问题。
jq -c '.Results[]' my.json | while read i; do
echo $i;
done
在 JSON 文件中,我正在使用 jq -c '.Results[]' 完美运行,但是当我使用 jq 对结果 $i 的操作在迭代时,我突然遇到几个解析错误。
是否有更好的方法来遍历 JSON 文件中的键值对? Ofcause 我可以只安装 Python/R 并进行典型的练习,但我真的希望它能在 shell 脚本中工作。
您可以使用 +
通过组合字段将两个对象相加;如果两个对象具有相同的对象,则使用右手对象的值。因此,如果您将现有对象设为 RHS:
jq '[ .Results[] | {Severity:"", InstalledVersion:"", FixedVersion:"", VulnerabilityID:""} + . ]' input.json
[
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1",
"VulnerabilityID": ""
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "",
"VulnerabilityID": ""
},
{
"Severity": "HIGH",
"InstalledVersion": "",
"FixedVersion": "",
"VulnerabilityID": "CVE-2016-2781"
}
]
另一种将回退添加到空字符串的方法:
[ .Results[] | . + { VulnerabilityID: (.VulnerabilityID // ""), FixedVersion: (.FixedVersion // ""), InstalledVersion: (.InstalledVersion // "") } ]
[
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"FixedVersion": "1.21.1ubuntu2.1",
"VulnerabilityID": ""
},
{
"Severity": "LOW",
"InstalledVersion": "1.21.1ubuntu2",
"VulnerabilityID": "",
"FixedVersion": ""
},
{
"Severity": "HIGH",
"VulnerabilityID": "CVE-2016-2781",
"FixedVersion": "",
"InstalledVersion": ""
}
]
Online demo
还有一个变化
jq '[
.Results[]
| .FixedVersion //= ""
| .VulnerabilityID //= ""
| .InstalledVersion //= ""
]' file.json
更通用的方法:
jq '.Results |
(map(keys)|add|unique|map({key:.,value:""})|from_entries) as $default |
map($default + .)
' input.json
解释:
1) map(keys)|add|unique
gets all the keys. If it's a subset you are interested, you can substitute it with :
["FixedVersion", "VulnerabilityID", "InstalledVersion"]
2) map({key:.,value:""})|from_entries) as $default
constructs a default object with all (or selected) keys.
3) $default + .
adds a key from default object if the key does not exist.