2015-11-23 10 views

Odpowiedz

5

Jeśli jq -s . *.json > output.json tworzy "zbyt długą listę argumentów"; mógłbyś fix it using zargs in zsh:

$ zargs *.json -- cat | jq -s . > output.json 

że można naśladować stosując find jak pokazano na @chepner's answer:

$ find -maxdepth 1 -name \*.json -exec cat {} + | jq -s . > output.json 

"Data in jq is represented as streams of JSON values ... This is a cat-friendly format - you can just join two JSON streams together and get a valid JSON stream.":

$ echo '{"a":1}{"b":2}' | jq -s . 
[ 
    { 
    "a": 1 
    }, 
    { 
    "b": 2 
    } 
] 
2

[edytowane używać find]

Oczywistą rzeczą do rozważenia będzie przetwarzać jeden plik na raz, a potem "slurp" im:

$ while read f ; cat "$f" ; done <(find . -maxdepth 1 -name "*.json") | jq -s . 

to jednak przypuszczalnie wymagać dużo pamięciowy. W ten sposób następuje może być bliżej, co trzeba:

#!/bin/bash 
# "slurp" a bunch of files 
# Requires a version of jq with 'inputs'. 
echo "[" 
while read f 
do 
    jq -nr 'inputs | (., ",")' $f 
done < <(find . -maxdepth 1 -name "*.json") | sed '$d' 
echo "]" 
+0

To nie jest dla mnie oczywiste, że mogę to zrobić, ponieważ AFAIK to, co robiłem, to wzięcie kilku pojedynczych obiektów Json '{...}' i umieszczenie ich w dobrze uformowanej tablicy obiektów [{...}, {...}, {...}] '. czy to się nadal dzieje z tym, co proponujesz? – Kristian

+1

[Nie używaj 'ls' w ten sposób] (http://mywiki.wooledge.org/ParsingLs). Możesz po prostu użyć pętli 'for' zamiast:' for f in * .json; zrobić kota "$ f"; zrobione | jq -s '.''. (Faktycznie, 'ls * .json' nie powiedzie się z tego samego powodu co oryginał: zbyt wiele argumentów linii poleceń wynikających z rozszerzenia nazwy ścieżki.) – chepner

+0

Nie polecałbym używania' find' w ten sposób, chociaż Naprawdę tylko stwarza problem, jeśli jeden z plików JSON miał znak nowej linii w swojej nazwie.Niektóre inne nazwy plików mogą być problematyczne, ale mogą być obsługiwane za pomocą 'IFS = read -r f' zamiast tego. – chepner

1

Problemem jest to, że długość linii poleceń jest ograniczona, a *.json produkuje zbyt wiele argumentów za jednym wierszu poleceń. Jednym rozwiązaniem jest rozbudować wzór w for pętli, które nie mają znaczenia takie same ograniczenia jak w linii polecenia ponieważ bash może iteracyjnego wyniku wewnętrznie zamiast konstruowania listę argumentów na polecenie zewnętrznej:

for f in *.json; do 
    cat "$f" 
done | jq -s '.' > output.json 

Jest to raczej nieefektywne, ponieważ wymaga jednorazowego uruchomienia cat dla każdego pliku. Bardziej wydajnym rozwiązaniem jest użycie find do wywoływania cat z jak największą liczbą plików za każdym razem.

find . -name '*.json' -exec cat '{}' + | jq -s '.' > output.json 

(może być w stanie po prostu użyć

find . -name '*.json' -exec jq -s '{}' + > output.json 

jak dobrze, może to zależeć od tego, co jest w plikach i jak wiele połączeń do jq używając opcji -s porównuje się do jednego połączenia.)

+0

Niestety, nie jest to replikacja pożądanego zachowania opcji -q "-s". (Opcja "slurp" tworzy tablicę JSON ze * strumienia * jednostek JSON.) – peak

+0

Prawdopodobnie można to naprawić, wyprowadzając wynik końcowej komendy 'find' do odpowiedniego wywołania' jq' ('jq '. [] | [.] "'?), ale prawdopodobnie nie jest warte wysiłku, aby to naprawić. – chepner

Powiązane problemy