2013-10-22 17 views
53

Używam narzędzi jq (jq-json-processor) w skrypcie powłoki do parsowania json.Jak połączyć 2 pliki json za pomocą jq?

mam 2 pliki json i scalić je w jeden unikalny plik

tu zawartości plików:

plik1

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

plik2

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

oczekiwany wynik

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

Staram dużo combinaison ale jedynym rezultatem ja dostać jest następujący, który nie jest oczekiwany wynik:

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

poleceniem:

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

Czy próbowałeś jsontool? https://github.com/trentm/json –

+0

Jeszcze nie, przyjrzę się. Thx – Janfy

+0

Aby to zrobić używając 'json' użyj:' cat f1 f2 | json --deep-merge' – xer0x

Odpowiedz

50

od 1,4 to jest możliwe z operatorem *. Kiedy otrzymają dwa obiekty, scalą je rekurencyjnie.Na przykład,

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

dostanie wam:

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

Jeśli też chcesz pozbyć się innych klawiszy (jak twój oczekiwanego rezultatu), jednym ze sposobów, aby to zrobić jest to:

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

Lub prawdopodobnie nieco bardziej efektywny (ponieważ nie łączą wszelkie inne wartości):

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

_NOTE_: flaga '-s' jest ważna, ponieważ bez niej dwa obiekty nie znajdują się w tablicy. –

20

Kto wie, czy nadal go potrzebujesz, ale tutaj jest rozwiązanie.

Po przejściu do opcji --slurp jest to łatwe!

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

Następnie operator + będą robić to, co chcesz:

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

(Uwaga: jeśli chcesz połączyć wewnętrzne obiektów zamiast po prostu nadpisywania lewych plików z prawem tych plików, to będzie trzeba to zrobić ręcznie)

30

Użyj jq -s add:

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

To czyta wszystkie teksty JSON ze standardowego wejścia do tablicy (jq -s), a następnie "redukuje" je.

(add jest zdefiniowana jako def add: reduce .[] as $x (null; . + $x);, które iteruje wartości tablicy wejściowego/obiektów i dodaje je. Obiekt dodanie == seryjnej.)

+4

Czy jest możliwe wykonanie rekurencyjnego scalenia (* operator) z tym podejściem? –

+0

@DaveFoster Tak, z czymś takim jak 'zmniejsz. [] Jako $ x ({};. * $ X)' - patrz także [odpowiedź jrib'a] (http://stackoverflow.com/a/36218044/1797912). – Chriki

2

Po pierwsze, {"wartość": .value} można skrócić do zaledwie {wartość}.

Po drugie, opcja --argfile (dostępna w jq 1.4 i jq 1.5) może być interesująca, ponieważ pozwala uniknąć konieczności użycia opcji --slurp.

Umieszczenie ich razem, te dwa obiekty w dwóch plikach mogą być łączone w określony sposób, co następuje:

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

Oto wersja, która działa rekursywnie (używając *) na dowolnej liczby obiektów:

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