2013-10-22 35 views
53

Sto usando gli strumenti jq (jq-json-processor) nello script di shell per analizzare json.Come unire 2 file json usando jq?

ho 2 file JSON e vogliono unirli in un unico file

Ecco il contenuto dei file:

file1

{ 
    "value1": 200, 
    "timestamp": 1382461861, 
    "value": { 
     "aaa": { 
      "value1": "v1", 
      "value2": "v2" 
     }, 
     "bbb": { 
      "value1": "v1", 
      "value2": "v2" 
     }, 
     "ccc": { 
      "value1": "v1", 
      "value2": "v2" 
     } 
    } 
} 

file2

{ 
    "status": 200, 
    "timestamp": 1382461861, 
    "value": { 
     "aaa": { 
      "value3": "v3", 
      "value4": 4 
     }, 
     "bbb": { 
      "value3": "v3" 
     },  
     "ddd": { 
      "value3": "v3", 
      "value4": 4 
     } 
    } 
} 

risultato atteso

{ 
    "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 
     } 
    } 
} 

cerco un sacco di combinaison ma l'unico risultato che ottiene è il seguente, che non è il risultato atteso:

{ 
    "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" 
    } 
} 

Utilizzando questo comando:

jq -s '.[].value' file1 file2 
+1

Hai provato jsontool? https://github.com/trentm/json –

+0

Non ancora, darò un'occhiata. Thx – Janfy

+0

Per fare ciò con 'json' usa:' cat f1 f2 | json --deep-merge' – xer0x

risposta

50

Poiché 1.4 è ora possibile con l'operatore *. Quando vengono dati due oggetti, li unirà ricorsivamente.Ad esempio,

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

si otterrebbe:

{ 
    "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 
} 

Se vuoi anche per sbarazzarsi degli altri tasti (come il vostro risultato atteso), un modo per farlo è questo:

jq -s '.[0] * .[1] | {value: .value}' file1 file2 

O le presumibilmente un po 'più efficace (in quanto non si fondono tutti gli altri valori):

jq -s '.[0].value * .[1].value | {value: .}' file1 file2 
+0

_NOTA: il flag '-s' è importante perché senza di esso i due oggetti non sono in una matrice. –

20

Chissà se ne hai ancora bisogno, ma ecco la soluzione.

Una volta raggiunta l'opzione --slurp, è facile!

--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. 

Poi l'operatore + farà ciò che si vuole:

jq -s '.[0] + .[1]' config.json config-user.json 

(Nota: se si desidera unire oggetti interni invece di sovrascrivere quelli dei file di sinistra con quelle dei file a destra, si bisogno di farlo manualmente)

30

Uso jq -s add:

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

Questo legge tutti i testi JSON dallo stdin in un array (lo fa jq -s) quindi li "riduce".

(add è definita come def add: reduce .[] as $x (null; . + $x);, che itera sui valori della matrice di input/dell'oggetto e li aggiunge. Oggetto aggiunta == unione.)

+4

È possibile eseguire l'unione ricorsiva (* operatore) con questo approccio? –

+0

@DaveFoster Sì, con qualcosa come 'reduce. [] Come $ x ({};. * $ X)' - vedi anche [risposta di Jrib] (http://stackoverflow.com/a/36218044/1797912). – Chriki

2

Innanzitutto, {"valore": .valore} può essere abbreviato a solo {valore}.

In secondo luogo, l'opzione --argfile (disponibile in jq 1.4 e jq 1.5) può essere di interesse in quanto evita di dover utilizzare l'opzione --slurp.

Mettendo questi insieme, i due oggetti in due file possono essere combinati in modo specificato come segue:

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

Ecco una versione che funziona in modo ricorsivo (utilizzando *) su un numero arbitrario di oggetti:

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