2013-10-22 46 views
53

我在shell脚本中使用jq工具(jq-json-processor)来解析json。如何使用jq合并2个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 
     } 
    } 
} 

我尝试了很多combinaison的,但唯一的结果我得到的是下面的,这是不期望的结果:

{ 
    "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 
+1

你试过jsontool吗? https://github.com/trentm/json –

+0

还没有,我去看看。 Thx – Janfy

+0

用'json'做到这一点:'cat f1 f2 | json --deep-merge' – xer0x

回答

50

由于1.4,这是现在能够与操作者*。当给定两个对象时,它会递归地合并它们。例如,

jq -s '.[0] * .[1]' file1 file2 

会让你:

{ 
    "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 
+0

_注意:'-s'标志非常重要,因为没有它,两个对象不在数组中。 –

20

谁知道你是否仍然需要它,但这里是解决方案。

一旦你得到--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 

(注意:如果要合并内的对象,而不是只用正确的文件那些覆盖左边的文件的,你会需要做手工)

30

使用jq -s add

$ echo '{"a":"foo","b":"bar"} {"c":"baz","a":0}' | jq -s add 
{ 
    "a": 0, 
    "b": "bar", 
    "c": "baz" 
} 

这将所有JSON文本从stdin读入数组(jq -s这样做),然后它“减少”它们。

add被定义为def add: reduce .[] as $x (null; . + $x);,其迭代输入数组的/对象的值,并增加了它们。对象增加==合并。)

+4

是否有可能使用这种方法进行递归合并(*运算符)? –

+0

@DaveFoster是的,用'reduce。[]作为$ x({};。* $ x)'' - 另请参阅[jrib's answer](http://stackoverflow.com/a/36218044/1797912)。 – Chriki

2

首先,{“value”:.value}可以缩写为{value}。其次,--argfile选项(可用于jq 1.4和jq 1.5)可能很有用,因为它避免了必须使用--slurp选项。

把这些结合在一起,在这两个文件中的两个对象可以在指定的方式进行组合如下:

$ jq --argfile o1 file1 --argfile o2 file2 '$o1 * $o2 | {value}' 
9

下面是在对象上任意数量的工作递归(使用*)版本:

echo '{"A": {"a": 1}}' '{"A": {"b": 2}}' '{"B": 3}' | jq --slurp 'reduce .[] as $item ({}; . * $item)' 
{ 
    "A": { 
    "a": 1, 
    "b": 2 
    }, 
    "B": 3 
}