如何使用 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 对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用公共密钥合并 2 个 json 文件

如何将2个文本文件合并到一个文件中?

合并来自 2 个 jQuery 片段的功能

将来自 2 个 mongoDB 集合的数据合并到 1 个文档中

如何在 blynk (arduino) 中合并 2 个文件

JQ 如何将多个对象合并为一个