Используя jq для извлечения значений и формата в CSV

Когда Вы уже получили ответ от @mdpc, который я просто обеспечу мнению Вашей исходной проблеме. Я не шел бы по этой дороге, поскольку это открывает кучу проблем, и Ваши программы в целом должны работать на всех системах (также проверка, если Ваша система все еще работает, если Вы работаете в другом локальном). Вы не должны также действительно полагаться на вывод/команды самостоятельно, но использовать соответствующий API для получения доступ/изменения к информации.

Так или иначе вот некоторые пути, которые могли помочь смягчить Вашу проблему:

  1. Используйте управление конфигурацией и укажите, какие программы/библиотеки должны быть установлены на машине. Можно обычно также указывать номер версии. Другая большая вещь об использовании управления конфигурацией состоит в том, что можно обычно получать всю информацию о системе, т.е. какое ядро работает, сколько NICs находится в системе и т.д.
  2. В зависимости от языка программирования Вы используете Вас, может хотеть изучить виртуализированные среды, т.е. bundler для рубина или virtualenv для Python.
  3. Используйте chroots для установки среды к определенным потребностям или (еще лучше)
  4. Просто поставьте свою среду как образ виртуальной машины
59
19.10.2016, 14:53
8 ответов

Поскольку Вы пометили этот python и предположили, что файл json имеет имя x.json

import os, json
with open('x.json') as f:
    x  = json.load(f)
    print '{}{}{}'.format(', '.join(y['displayName'] for y in x['data']), os.linesep,
             ', '.join(y['value'] for y in x['data']))
First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE
2
27.01.2020, 19:33

Хотя мне пришлось удалить последнюю запятую во входных данных Вашего примера, чтобы он заработал, потому что jq жаловался на ожидание другого элемента массива, это:

INPUT | jq -r '[.[][].displayName], [.[][].value]| join(", ")'

... заставило меня.....

First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE

Как это работает в двух словах:

  1. я перешел на третий уровень объектов данных, используя форму пустого [] индексного поля и .dot нотацию.
  2. Однажды достаточно глубоко я указал поля данных, которые мне нужны по имени, например, .[][][].displayName.
  3. Я заверил, что мои желаемые поля самоустанавливаются, вернув их как отдельные объекты массива, такие как [.[][].displayName], [.[][].value]
  4. , а затем отправил эти объекты в функцию join(", "), чтобы они были объединены как отдельные сущности.

На самом деле выполнение [.field] - это всего лишь другой путь к map(.field), но это немного более специфический способ, так как он задает уровень глубины для получения желаемых данных.

1
27.01.2020, 19:33

В дополнение к уже предложенным причинам, это может быть также следующим образом:

  • другой диск монтируется «поверх» существующей папки, которая полна данных
  • du рассчитает размер затраченного монтируемого диска и df покажет действительно потраченное
  • решение: (по возможности) демонтировать все не корневые диски и проверить размер с du -md 1 снова. Исправьте ситуацию, переместив скрытую папку в другое место или установите в другое место.
-121--198683-

Учитывая только этот файл, вы можете сделать что-то вроде:

<testfile jq -r '.data | map(.displayName), map(.value) | join(", ")'

. Оператор выбирает поле из объекта/хэша. Таким образом, мы начинаем с .data , который возвращает массив с данными в нем. Затем дважды сопоставляем массив, сначала выбирая displayName, затем выбираем значение, давая нам два массива с только значениями этих ключей. Для каждого массива мы соединяем элементы с «», образуя две строки. Аргумент -r указывает jq не цитировать результирующий последовательности.

Если ваш фактический файл длиннее (т.е. содержит записи для более чем одного человека), вам, вероятно, потребуется что-то немного сложнее.

-121--7553-

Я обнаружил, что jq трудно обернуть голову. Вот некоторые Ruby:

ruby -rjson -rcsv -e '
  data = JSON.parse(File.read "file.json")
  data["data"].collect {|item| [item["displayName"], item["value"]]}
              .transpose
              .each {|row| puts row.to_csv}
'
First Name,Last Name,Position,Company Name,Country
VALUE,VALUE,VALUE,VALUE,VALUE

Синтаксический анализатор ruby JSON пробил про запятую перед закрывающей скобкой.

11
27.01.2020, 19:33

Учитывая только этот файл, вы можете сделать что-то вроде:

<testfile jq -r '.data | map(.displayName), map(.value) | join(", ")'

. Оператор выбирает поле из объекта / хеша. Таким образом, мы начинаем с .data , что возвращает массив с данными в нем. Затем мы дважды отображаем на массиве, сначала выбирая имя отображения, а затем выбирая значение, давая нам два массива только с значениями этих клавиш. Для каждого массива мы присоединяемся к элементам с «», образуя две строки. Аргумент -R -R JQ не процитировать полученные строки.

Если ваш фактический файл дольше (т. Е. Есть записи для более чем одного человека), вы, вероятно, понадобится что-то более сложное.

30
27.01.2020, 19:33

jq имеет фильтр @csv для преобразования массива в строку CSV. Этот фильтр учитывает большинство сложностей, связанных с форматом CSV, начиная с запятых, встроенных в поля. (jq 1.5 имеет аналогичный фильтр, @tsv, для создания файлов значений, разделенных табуляцией.)

Конечно, если все заголовки и значения гарантированно свободны от запятых и двойных кавычек, тогда может не быть необходимо использовать фильтр @csv. В противном случае, наверное, лучше было бы его использовать.

Например, если «Название компании» было «Смит, Смит и Смит», и если другие значения были такими, как показано ниже, вызов jq с параметром «-r» приведет к созданию действительного CSV:

$ jq -r '.data | map(.displayName), map(.value) | @csv' so.json2csv.json
"First Name","Last Name","Position","Company Name","Country"
"John (""Johnnie"")","Doe","Director, Planning and Posterity","Smith, Smith and Smith","Transylvania"
51
27.01.2020, 19:33

При каждом изменении конфигурации добавьте суффикс, кратко описывающий конфигурацию, в поле EXTRAVERSION файла Makefile.

EXTRAVERSION=-lpae

и другое время

EXTRAVERSION=-486

Что пути различные конфигурации являются различными версиями, поскольку задействованы все инструменты: разные выходные данные из uname -r , различные подкаталоги в /lib/modules и т. д.

Именно это делают большинство дистрибутивов.

-121--184840-

Ответ дан в комментарии перечислять рассылки Штефана Дёсингера под названием Wine 64 bit

OSX имеет ABI несовместимость с Win64 - OSX перезаписывает регистр CPU, который Win64 приложения ожидают, что останется нетронутым. Apple не может изменить ABI, так как уже существуют 64-разрядные приложения OSX, которые ожидают, что все будет работать путь. Потенциальным обходным путем может быть запуск Wine внутри эмулятора CPU, как qemu, но это все, кроме просто.

-121--54778-

Я предпочитаю делать каждую запись строкой в моем CSV.

jq '.data | map([.displayName, .rank, .value] | join(", ")) | join("\n")'
33
27.01.2020, 19:33

Мне нравится jq , но это не инструмент для преобразования JSON в CSV. Чтобы сделать что-нибудь с CSV, рассмотрите:

  • csvkit:достойный универсальный -инструментарий CSV, имеет in2csv , который может преобразовывать JSON в CSV
  • GoCSV:похож на csvkit, но я бы сказал «более округлый -»; имеет транспонирование , что и требуется для этой задачи

Эта запятая после последнего объекта («Страна» )в массиве создает проблемы для jq , поэтому я удалил ее вручную.

Вот полный конвейер для получения желаемого результата,

% jq '.data' < so.json        # Get just the array of objects
| in2csv -f json -I           # Convert array-of-objects to rows-with-fields
| gocsv transpose             # "Rotate" table
| gocsv tail -n 1             # Cut out rank
| gocsv select -c 1 -exclude  # Cut out JSON property names

и вы получите,

First Name,Last Name,Position,Company Name,Country
VALUE,VALUE,VALUE,VALUE,VALUE

После команды jq , которая просто приводит нас к данным, вот вывод на каждом этапе:

in2csv -f json -I:

Каждый объект становится строкой, и каждое свойство объекта является его собственным полем; -Iчтобы не выводить типы данных (оставьте любое значение, поскольку -равно ).

displayName,rank,value
First Name,1,VALUE
Last Name,2,VALUE
Position,3,VALUE
Company Name,4,VALUE
Country,5,VALUE

gocsv transpose:

Первый столбец становится заголовком, а каждый последующий столбец становится строкой.

displayName,First Name,Last Name,Position,Company Name,Country
rank,1,2,3,4,5
value,VALUE,VALUE,VALUE,VALUE,VALUE

gocsv tail -n 1:

Начиная с нижнего ряда, сохранить "1 ряд вверх" (только этот нижний ряд ); эффективно вырезал ранг .

displayName,First Name,Last Name,Position,Company Name,Country
value,VALUE,VALUE,VALUE,VALUE,VALUE

gocsv select -c 1 -exclude:

Наконец, исключите первый столбец; эффективное вырезание имен свойств объекта из исходного JSON.

First Name,Last Name,Position,Company Name,Country
VALUE,VALUE,VALUE,VALUE,VALUE
1
18.10.2021, 21:46

Старый вопрос, но кажется, что все ответы рекомендуют индексировать по displayName, что для меня не имеет смысла. CSV — это не индексированный формат, это список строк, поэтому нелогично, что вам нужно что-то индексировать. Единственным исключением является https://unix.stackexchange.com/a/673753/488462, который я бы предпочел на практике, за исключением того, что он использует csvkit, а вопрос явно касается jq.

Так вот jq -единственный путь в два шага:

  • Построить заголовок:cat data.json | jq '.[0] | keys_unsorted | @csv' > data.csv
  • Преобразование значений:cat data.json | jq '.[] | map(values) | @csv' >> data.csv

Вы можете объединить их в одну команду с помощью teeили создать сложный jq-запрос, который делает обе вещи, если хотите, но я думаю, что эта версия уже достаточно хороша.

Обратите внимание, что вы должны использовать keys_unsorted, потому что keysбудет сортировать ваши ключи (, а valuesне ), что приведет к несоответствию столбцов. Кроме того, хотя обычно людям нужны оба шага, технически формат CSV не требует заголовка -, это просто необязательное удобство (и не всегда желательно ). Таким образом, в этих случаях вы можете опустить заголовок.

Наконец, входные данные вашего примера без необходимости заключены в объект с именем data. Я предполагаю, что вы распаковываете это с помощью тривиальной команды, такой как cat input.json | jq '.data' > data.json, так как это не имеет отношения к тому, что запрашивается (для преобразования в CSV ).

1
17.11.2021, 18:57

Теги

Похожие вопросы