J'utilise les outils jq (jq-json-processeur) du script shell pour analyser json.
J'ai 2 fichiers json et veux les fusionner en un fichier unique
Voici le contenu des fichiers:
fichier1
{
"value1": 200,
"timestamp": 1382461861,
"value": {
"aaa": {
"value1": "v1",
"value2": "v2"
},
"bbb": {
"value1": "v1",
"value2": "v2"
},
"ccc": {
"value1": "v1",
"value2": "v2"
}
}
}
fichier2
{
"status": 200,
"timestamp": 1382461861,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
},
"bbb": {
"value3": "v3"
},
"ddd": {
"value3": "v3",
"value4": 4
}
}
}
résultat attendu
{
"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
}
}
}
J'essaie beaucoup de combinaisons mais le seul résultat obtenu est le suivant, qui n'est pas le résultat attendu:
{
"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"
}
}
En utilisant cette commande:
jq -s '.[].value' file1 file2
Depuis la version 1.4, cela est maintenant possible avec le *
_ opérateur. Lorsque deux objets sont donnés, il les fusionnera de manière récursive. Par exemple,
jq -s '.[0] * .[1]' file1 file2
Vous obtiendriez:
{
"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
}
Si vous souhaitez également vous débarrasser des autres clés (comme le résultat attendu), vous pouvez le faire comme suit:
jq -s '.[0] * .[1] | {value: .value}' file1 file2
Ou le supposé un peu plus efficace (car il ne fusionne aucune autre valeur):
jq -s '.[0].value * .[1].value | {value: .}' file1 file2
Utilisez jq -s add
:
$ echo '{"a":"foo","b":"bar"} {"c":"baz","a":0}' | jq -s add
{
"a": 0,
"b": "bar",
"c": "baz"
}
Ceci lit tous les textes JSON de stdin dans un tableau (jq -s
Le fait) puis les "réduit".
(add
est défini comme def add: reduce .[] as $x (null; . + $x);
, qui parcourt les valeurs/object du tableau en entrée et les ajoute. Ajout d'objet == fusion.)
Qui sait si vous en avez encore besoin, mais voici la solution.
Une fois arrivé au --Slurp
option, c'est 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.
Puis le +
l'opérateur va faire ce que vous voulez:
jq -s '.[0] + .[1]' config.json config-user.json
(Remarque: si vous souhaitez fusionner des objets internes au lieu de simplement écraser ceux de fichier gauche avec ceux de fichier de droite, vous devrez le faire manuellement.)
Voici une version qui fonctionne de manière récursive (en utilisant *
) sur un nombre arbitraire d'objets:
echo '{"A": {"a": 1}}' '{"A": {"b": 2}}' '{"B": 3}' | jq --Slurp 'reduce .[] as $item ({}; . * $item)'
{
"A": {
"a": 1,
"b": 2
},
"B": 3
}
Premièrement, {"valeur":. Valeur} peut être abrégé en {valeur}.
Deuxièmement, l'option --argfile (disponible dans jq 1.4 et jq 1.5) peut être intéressante car elle évite d'avoir à utiliser l'option --Slurp.
En regroupant ces éléments, les deux objets des deux fichiers peuvent être combinés de la manière spécifiée comme suit:
$ jq -n --argfile o1 file1 --argfile o2 file2 '$o1 * $o2 | {value}'
Le drapeau '-n' indique à jq de ne pas lire stdin, car les entrées proviennent des options --argfile ici.