如何用JQ合并两个数组变量并实现旧值覆盖?
问题分析
你之前碰到两个核心问题:一是用--arg传递JSON数组时,jq会把它当成字符串处理,导致数组和字符串无法相加的类型错误;二是换成--argjson后,简单的+操作只是拼接数组,没法自动去重并覆盖重复Key的元素。
解决方案
这里提供两种可靠的实现方式,都能满足「用第二个数组覆盖第一个数组重复Key的值,同时保留唯一Key元素」的需求:
方式一:对象合并法(推荐,性能更优)
这种方式通过将数组转换为Key映射的对象,利用jq的对象合并特性实现覆盖,再转换回数组格式:
#!/bin/bash -e firstArrayVariable=' [ { "Key": "A B", "Value": "1 2" }, { "Key": "C D", "Value": "3 4" }, { "Key": "E F", "Value": "5 6" }, { "Key": "G H", "Value": "9 10" } ] ' secondArrayVariable=' [ { "Key": "A B", "Value": "1 2" }, { "Key": "C D", "Value": "3 4" }, { "Key": "G H", "Value": "11 12" }, { "Key": "J K", "Value": "15 16" } ] ' jq \ --indent 2 \ --argjson second "$secondArrayVariable" \ ' ($ | from_entries) * ($second | from_entries) | to_entries | map({Key: .key, Value: .value}) ' <<< "${firstArrayVariable}"
逻辑拆解:
--argjson second "$secondArrayVariable":正确传递JSON数组,让jq直接识别为JSON类型,彻底避免字符串类型错误。($ | from_entries):将输入的第一个数组转换为{"Key值": "Value值"}的对象结构,把Key字段作为对象的键,方便后续合并操作。* ($second | from_entries):使用*操作符合并两个对象,后面的对象会覆盖前面对象中相同键的值,完美实现「用第二个数组的新值覆盖第一个数组对应值」的核心需求。| to_entries:将合并后的对象转换回键值对数组(结构为[{"key": "...", "value": "..."}])。| map({Key: .key, Value: .value}):把字段名从默认的key/value改回原始的Key/Value,匹配你需要的输出格式。
方式二:分组取最后元素法(逻辑更直观)
如果觉得对象转换有点绕,也可以用数组拼接+分组的方式实现:
jq \ --indent 2 \ --argjson second "$secondArrayVariable" \ '($second + .) | group_by(.Key) | map(last)' \ <<< "${firstArrayVariable}"
逻辑拆解:
$second + .:把第二个数组放在前面,和第一个数组拼接(这样重复Key的元素中,第二个数组的版本位置更靠后)。group_by(.Key):按Key字段对拼接后的数组分组,每个组包含所有相同Key的元素。map(last):取每个分组的最后一个元素,也就是第二个数组中的版本,实现覆盖效果。
输出结果
两种方式都会输出你期望的结果:
[ { "Key": "A B", "Value": "1 2" }, { "Key": "C D", "Value": "3 4" }, { "Key": "E F", "Value": "5 6" }, { "Key": "G H", "Value": "11 12" }, { "Key": "J K", "Value": "15 16" } ]
内容的提问来源于stack exchange,提问作者Nam Nguyen
相关产品推荐
相关产品推荐

