如何使用 jq 合并来自 2 个文件的 2 个 JSON 对象?
Posted
技术标签:
【中文标题】如何使用 jq 合并来自 2 个文件的 2 个 JSON 对象?【英文标题】:How to merge 2 JSON objects from 2 files using jq? 【发布时间】:2013-11-01 00:30:17 【问题描述】:我在 shell 脚本中使用jq 工具(jq-json-processor)来解析 json。
我有 2 个 json 文件,想将它们合并到一个唯一的文件中
这里是文件内容:
文件1
"value1": 200,
"timestamp": 1382461861,
"value":
"aaa":
"value1": "v1",
"value2": "v2"
,
"bbb":
"value1": "v1",
"value2": "v2"
,
"ccc":
"value1": "v1",
"value2": "v2"
文件2
"status": 200,
"timestamp": 1382461861,
"value":
"aaa":
"value3": "v3",
"value4": 4
,
"bbb":
"value3": "v3"
,
"ddd":
"value3": "v3",
"value4": 4
预期结果
"value":
"aaa":
"value1": "v1",
"value2": "v2",
"value3": "v3",
"value4": 4
,
"bbb":
"value1": "v1",
"value2": "v2",
"value3": "v3"
,
"ccc":
"value1": "v1",
"value2": "v2"
,
"ddd":
"value3": "v3",
"value4": 4
我尝试了很多组合,但我得到的唯一结果是以下,这不是预期的结果:
"ccc":
"value2": "v2",
"value1": "v1"
,
"bbb":
"value2": "v2",
"value1": "v1"
,
"aaa":
"value2": "v2",
"value1": "v1"
"ddd":
"value4": 4,
"value3": "v3"
,
"bbb":
"value3": "v3"
,
"aaa":
"value4": 4,
"value3": "v3"
使用这个命令:
jq -s '.[].value' file1 file2
【问题讨论】:
你试过jsontool吗? github.com/trentm/json 使用json
执行此操作:cat f1 f2 | json --deep-merge
你在哪里/如何得到json
@xer0x?
@Gus 哦,要获得json
工具,请转到github.com/trentm/json
【参考方案1】:
从 1.4 开始,现在可以使用 *
运算符来实现。当给定两个对象时,它将递归地合并它们。例如,
jq -s '.[0] * .[1]' file1 file2
重要提示:注意-s (--slurp)
标志,它将文件放在同一个数组中。
会得到你:
"value1": 200,
"timestamp": 1382461861,
"value":
"aaa":
"value1": "v1",
"value2": "v2",
"value3": "v3",
"value4": 4
,
"bbb":
"value1": "v1",
"value2": "v2",
"value3": "v3"
,
"ccc":
"value1": "v1",
"value2": "v2"
,
"ddd":
"value3": "v3",
"value4": 4
,
"status": 200
如果您还想摆脱其他键(如您的预期结果),一种方法是:
jq -s '.[0] * .[1] | value: .value' file1 file2
或者可能更有效(因为它不合并任何其他值):
jq -s '.[0].value * .[1].value | value: .' file1 file2
【讨论】:
注意:-s
标志很重要,因为没有它,这两个对象不在一个数组中。
@SimoKinnunen 这里我们合并两个 json 文件。是否可以有 1 个 json 变量和其他 json 文件。我试过了,但它似乎不适合我!
如果单个文件按键排序,是否可以在生成的文件中保留顺序?
@SimoKinnunen 我正在使用这个命令:“jq -s 'add' config.json other/*.json”但是当我执行“cat config.json”时它没有被合并。如何将输出放回文件中?
请注意,value: .value
可以缩短为 value
。【参考方案2】:
使用jq -s add
:
$ echo '"a":"foo","b":"bar" "c":"baz","a":0' | jq -s add
"a": 0,
"b": "bar",
"c": "baz"
这会将所有 JSON 文本从标准输入读取到一个数组中(jq -s
会这样做),然后“减少”它们。
(add
定义为def add: reduce .[] as $x (null; . + $x);
,它遍历输入数组/对象的值并将它们相加。对象添加 == 合并。)
【讨论】:
这种方法可以递归合并(*操作符)吗? @DaveFoster 是的,类似reduce .[] as $x (; . * $x)
- 另见jrib’s answer。【参考方案3】:
谁知道你是否还需要它,但这里是解决方案。
一旦您选择了--slurp
选项,就很容易了!
--slurp/-s:
Instead of running the filter for each JSON object in the input,
read the entire input stream into a large array and run the filter just once.
那么+
操作符会做你想做的事:
jq -s '.[0] + .[1]' config.json config-user.json
(注意:如果你想合并内部对象而不是仅仅用右侧文件覆盖左侧文件,你需要手动完成)
【讨论】:
【参考方案4】:这是一个在任意数量的对象上递归工作的版本(使用*
):
echo '"A": "a": 1' '"A": "b": 2' '"B": 3' |\
jq --slurp 'reduce .[] as $item (; . * $item)'
"A":
"a": 1,
"b": 2
,
"B": 3
【讨论】:
很好的答案。合并目录中的所有文件时效果很好:jq -s 'reduce .[] as $item (; . * $item)' *.json
我的 json 内容是一个对象数组,所以这对我有用:echo $JSON_ONE $JSON_TWO | jq -s 'flatten | group_by(keys[]) | map(reduce .[] as $item (; . * $item))'
【参考方案5】:
首先,"value": .value 可以缩写为 value。
其次,--argfile 选项(在 jq 1.4 和 jq 1.5 中可用)可能很有趣,因为它避免了使用 --slurp 选项。
把这些放在一起,两个文件中的两个对象可以按照指定的方式组合起来,如下:
$ jq -n --argfile o1 file1 --argfile o2 file2 '$o1 * $o2 | value'
'-n' 标志告诉 jq 不要从标准输入读取,因为输入来自此处的 --argfile 选项。
关于 --argfile 的注意事项
jq 手册弃用了--argfile
,因为它的语义很重要:如果指定的输入文件恰好包含一个 JSON 实体,则按原样读取该实体;否则,流中的项目将包装在一个数组中。
如果您对使用 --argfile 感到不自在,您可以考虑几种替代方法。这样做时,请确保使用--slurpfile
不会导致-s
命令行选项与多个文件一起使用时效率低下。
【讨论】:
jq 已弃用--argile
为 --slurpfile
【参考方案6】:
这可用于合并命令中指定的任意数量的文件:
jq -rs 'reduce .[] as $item (; . * $item)' file1.json file2.json file3.json ... file10.json
或者这个对于任意数量的文件
jq -rs 'reduce .[] as $item (; . * $item)' ./*.json
【讨论】:
以上是关于如何使用 jq 合并来自 2 个文件的 2 个 JSON 对象?的主要内容,如果未能解决你的问题,请参考以下文章