使用 jq 合并四个新行分隔的 json 文件

使用 jq 合并四个新行分隔的 json 文件

我正在尝试合并 4 个 JSON 文件(将来可能还会有两个)。换行符分隔的 JSON 文件之间的唯一共同因素是“vulnid”。

File 1: 
{"vulnid":"cve1", "product":"product1"}
{"vulnid":"cve2", "product":"product2"}
{"vulnid":"cve3", "product":"product3"}
{"vulnid":"cve4", "product":""}
{"vulnid":"cve5", "product":""}
{"vulnid":"cve6", "product":""}

File 2: 
{"vulnid":"cve1", "version":"version1"}
{"vulnid":"cve2", "version":"version2"}
{"vulnid":"cve3", "version":"version3"}
{"vulnid":"cve4", "version":"version4"}

File 3: 
{"vulnid":"cve1", "patch":"patch1"}
{"vulnid":"cve2", "patch":"patch2"}
{"vulnid":"cve3", "patch":"patch3"}
{"vulnid":"cve4", "patch":""}

File 4: 
{"vulnid":"cve1", "speed":"speed1"}
{"vulnid":"cve2", "power":"power2"}
{"vulnid":"cve3", "amps":"amps3"}
{"vulnid":"cve4", "product":"product4"}
{"vulnid":"cve4", "patch":"patch4"}


Required output:
{"vulnid":"cve1", "product":"product1", "version":"version1", "patch":"patch1", "speed":"speed1"}
{"vulnid":"cve2", "product":"product2", "version":"version2", "patch":"patch2", "power":"power2"}
{"vulnid":"cve3", "product":"product3", "version":"version3", "patch":"patch3", "amps":"amps3"}
{"vulnid":"cve4", "product":"product4", "version":"version4", "patch":"patch4"}
{"vulnid":"cve5", "product":""}
{"vulnid":"cve6", "product":""}

到目前为止我已经尝试过:

jq -s '.[0] * .[1] * .[3] * .[4]' json1 json2 json3 json4
jq -s '.[0] + .[1] + .[3] + .[4]' json1 json2 json3 json4

...以及 jq 的多种不同组合,它们都提供了错误的结果,并证明了我不理解该工具的一点。

使用字段“vulnid”和 jq 是否有可能完成这种合并?

答案1

最短的jq解决方案:

jq -sc 'group_by(.vulnid)[] | add' file*.json

输出:

{"vulnid":"cve1","product":"product1","version":"version1","patch":"patch1","speed":"speed1"}
{"vulnid":"cve2","product":"product2","version":"version2","patch":"patch2","power":"power2"}
{"vulnid":"cve3","product":"product3","version":"version3","patch":"patch3","amps":"amps3"}
{"vulnid":"cve4","product":"product4","version":"version4","patch":"patch4"}
{"vulnid":"cve5","product":""}
{"vulnid":"cve6","product":""}

答案2

是的,我想是的。

如果我们更改数据,以便将字符串vulnid作为键,将对象本身作为相应的值(例如{"cve1": {"vulnid": "cve1", "product": "product1" }}),那么我们可以使用reduce*将具有相同键的字符串组合起来。下面的第一个map()生成了正确的格式reduce

因此,使用文件中的示例输入json

$ < json jq -s 'map({(.vulnid): . }) | reduce .[] as $item ({}; . * $item) '
{
  "cve1": {
    "vulnid": "cve1",
    "product": "product1",
    "version": "version1",
    "patch": "patch1",
    "speed": "speed1"
  },
  ...

然后,在对象周围放置绒毛以获得预期的输出就相当简单了:

$ < json jq -s 'map({(.vulnid): . }) | 
                    reduce .[] as $item ({}; . * $item) | map(.) | .[]'
{
  "vulnid": "cve1",
  "product": "product1",
  "version": "version1",
  "patch": "patch1",
  "speed": "speed1"
}
...

不过,如果有更好的方法来完成这一切,我不会感到惊讶。

相关内容