2013-10-22 89 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 
}