JQ создать вывод во многих отдельных файлах - PullRequest
0 голосов
/ 16 января 2019

с учетом следующего json:

    [
    {"_id":{"$oid":"6d2"},"jlo":"ΕΙ AJSB","dd":"d5f"},
    {"_id":{"$oid":"c6d3"},"jlo":"ΕΙ ALKSB","dd":"5d9"},
    {"_id":{"$oid":"b0cc6d4"},"jlo":"ΕΙ AGHTSB","dd":"1b1"},
    {"_id":{"$oid":"6d2"},"jlo":"ΕPOWΙ AJSB","dd":"d5f"},
    {"_id":{"$oid":"c6d3"},"jlo":"ΕGTΙ ALKSB","dd":"5d9"},
    {"_id":{"$oid":"b0cc6d4"},"jlo":"ΕLKΙ AGHTSB","dd":"1b1"}
    ]

что мне нужно сделать, это иметь в качестве выходных данных для каждого дискретного значения элемента ll уникальные значения ta в отдельном файле, названном в виде однозначного представления, где каждый код dd заменен представлением, читаемым человеком :

d5f:departmentone
5d9:departmentalt
1b1:departshort

Требуемый вывод для каждой строки каждого уникального значения jlo с количеством раз, которое он был найден в каждом элементе dd, поэтому в итоге мы получаем что-то вроде этого:

first file named departmentone.txt:
ΕΙ AJSB 1
ΕPOWΙ AJSB 1

second file named departmentalt.txt
ΕΙ ALKSB 1
ΕGTΙ ALKSB 1

third file named departshort.txt
ΕΙ AGHTSB 2

я пробовал с картой и уменьшением, group_by, sort_by, с очень плохими результатами

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Необходим только один вызов jq. Чтобы выделить выходные данные для отдельных файлов, вы можете объединить этот один вызов с одним вызовом для awk или использовать цикл оболочки, как показано ниже.

Во-первых, вот иллюстрация того, как будет выглядеть конвейер оболочки:

jq -r --rawfile dd2name dd2name.tsv -f group.jq input.json |
  while IFS=$'\t' read -r f v ; do echo "$v" >> "$f" ; done

Предполагается, что сопоставление с именами файлов находится в файле TSV с именем dd2name.tsv и что следующая группа jq находится в group.jq:

def dict:
  split("\n") | map(select(length>0) | split("\t"))
  | INDEX(.[0]) | map_values(.[1]);

($dd2name | dict) as $dict
| ($dict | keys_unsorted[]) as $dd
| map(select(.dd == $dd))
| group_by(.jlo)
| map("\($dict[$dd])\t\(.[0].jlo) \(length)")[]

Как следует из названия, функция dict создает словарь, дающий сопоставление значений .dd с именами файлов. Предполагается наличие INDEX. Если ваш jq не имеет INDEX, то сейчас самое время обновить ваш jq; в противном случае его def можно легко скопировать из builtin.jq (google: builtin.jq "def INDEX"), или вы можете заменить последнюю строку на: | reduce .[] as $p ({}; .[$p[0]] = $p[1]);

Решение на основе awk

Следующая команда awk может использоваться вместо приведенной выше команды while ... done:

awk -F\\t 'fn && (fn!=$1) {close(fn)}; {fn=$1; print $2 >> fn}'

Сезон по вкусу

Если файл отображения dd2name.tsv не содержит суффикс ".txt", его можно легко добавить любым из множества способов, в зависимости от вкуса.

Также обратите внимание, что предложенные решения выше делают некоторые предположения, в частности, что значения .jlo не содержат табуляции, новых строк или NUL. Если какое-либо из этих предположений нарушается, потребуется некоторая настройка.

0 голосов
/ 16 января 2019

Я бы сделал это за три прохода, отфильтровав массив с требуемым dd и сгруппировав по jlo, затем извлекая jlo первого (гарантированного) элемента массива и его длину:

map(select(.dd == "d5f")) | group_by(.jlo) | map("\(.[0].jlo) \(length)") | .[]

Вы можете попробовать здесь .

Полный запуск:

jq --arg dd d5f --raw-output 'map(select(.dd == $dd)) | group_by(.jlo) | map("\(.[0].jlo) \(length)") | .[]' yourJsonFile > departmentone.txt
jq --arg dd 5d9 --raw-output 'map(select(.dd == $dd)) | group_by(.jlo) | map("\(.[0].jlo) \(length)") | .[]' yourJsonFile > departmentalt.txt
jq --arg dd 1b1 --raw-output 'map(select(.dd == $dd)) | group_by(.jlo) | map("\(.[0].jlo) \(length)") | .[]' yourJsonFile > departmentshort.txt

Предположим, у вас есть файл с именем "mapping.txt" со следующим содержимым:

d5f:departmentone
5d9:departmentalt
1b1:departshort

Вы можете извлечь эти коды и метки для создания файлов:

while IFS=: read -r code label; do
    jq --arg dd $code --raw-output 'map(select(.dd == $dd)) | group_by(.jlo) | map("\(.[0].jlo) \(length)") | .[]' yourJsonFile > "$label".txt
done < mapping.txt
...