Вопрос или проблема
Недавно я открыл для себя jq
и gron
. Для моего случая использования gron
вполне достаточно, но меня немного беспокоит отсутствие разработки. Есть несколько ошибок, которые не были исправлены в течение года, в то время как я вижу, что jq
активно развивается.
Поэтому я хотел бы эмулировать gron
с помощью jq
. Я подозреваю, что это не слишком сложно, но мои знания jq
ограничены.
В качестве примера, я хотел бы использовать jq
, чтобы получить этот вывод:
T424f7496c3a01 -14889.86
demo -15030.785
из этого ввода:
{
"T424f7496c3a01": {
"remaining": -14889.86,
"ts": 136572.504
},
"demo": {
"remaining": -15030.785,
"ts": 0.515
}
}
Я придумал этот скрипт jq
, который это делает:
jq -r '[keys,([.[]|.remaining|round|"\t"+tostring])]|transpose|.[]|add'
но он гораздо менее читабелен, чем
gron | fgrep '.remaining = '
который выдает
json.T424f7496c3a01.remaining = -18079.105;
json.demo.remaining = -18220.029;
что можно легко разобрать в цикле IFS=" .=;" read
в bash
.
Поэтому я задаю вопрос о долгосрочной поддерживаемости: есть ли простой скрипт для jq
, который может дать мне что-то, легко разбираемое в bash
? Я боюсь, что через месяц, используя скрипт jq
выше, я не буду иметь представления, как он работает…
Преобразуйте входной объект в набор “записей” с помощью to_entries
. Каждая запись является объектом с ключом key
(ключ из объекта) и ключом value
(значение этого ключа в объекте).
Выделите .key
и соответствующее значение .value.remaining
из каждой записи и поместите их в массив, который вы передаете через @tsv
, чтобы получить список, разделенный табуляцией.
$ jq -r 'to_entries[] | [.key, .value.remaining] | @tsv' file
T424f7496c3a01 -14889.86
demo -15030.785
Вы можете прочитать это с помощью IFS=$'\t' read -r the_id remaining
в цикле, если захотите, при условии, что ключи не содержат буквальных табуляций или переносов строк.
С промежуточными результатами:
$ jq -r 'to_entries[]' file
{
"key": "T424f7496c3a01",
"value": {
"remaining": -14889.86,
"ts": 136572.504
}
}
{
"key": "demo",
"value": {
"remaining": -15030.785,
"ts": 0.515
}
}
$ jq -r 'to_entries[] | [.key, .value.remaining]' file
[
"T424f7496c3a01",
-14889.86
]
[
"demo",
-15030.785
]
$ jq -r 'to_entries[] | [.key, .value.remaining] | @tsv' file
T424f7496c3a01 -14889.86
demo -15030.785
Ответ или решение
Для эмуляции функциональности инструмента gron
с помощью jq
, мы можем использовать функцию to_entries
. Это позволит нам преобразовать входной объект в набор "записей", где каждая запись будет содержать ключ и значение. Далее мы можем извлечь нужные нам поля и вывести их в удобном формате.
Предположим, что у нас есть следующий ввод в формате JSON:
{
"T424f7496c3a01": {
"remaining": -14889.86,
"ts": 136572.504
},
"demo": {
"remaining": -15030.785,
"ts": 0.515
}
}
Чтобы получить желаемый вывод, как в примере с gron
, вы можете использовать следующий скрипт jq
:
jq -r 'to_entries[] | [.key, .value.remaining] | @tsv'
Объяснение работы скрипта:
-
to_entries[]
: Эта функция преобразует входной объект в массив объектов с двумя полями:key
иvalue
. Каждый объект в массиве будет представлять собой “запись” исходного JSON. -
[.key, .value.remaining]
: Здесь мы создаем новый массив, который содержит ключ и значениеremaining
из соответствующей записи. -
@tsv
: Эта функция форматирует массив как табулированную строку (TSV — Tab-Separated Values), что делает вывод удобным для дальнейшей обработки в bash.
Результат выполнения команды будет выглядеть так:
T424f7496c3a01 -14889.86
demo -15030.785
Теперь этот вывод легко разбирается в bash. Например, вы можете использовать следующий цикл для обработки полученных значений:
while IFS=$'\t' read -r the_id remaining; do
echo "ID: $the_id, Remaining: $remaining"
done < <(jq -r 'to_entries[] | [.key, .value.remaining] | @tsv' file.json)
Таким образом, вы получите читаемые и легко разборчивые результаты, при этом используя активное и поддерживаемое средство jq
. Это обеспечит более долгосрочную поддерживаемость вашего кода, по сравнению с gron
, который, как вы заметили, может иметь проблемы с обновлениями.
Если вам нужно добавить дополнительные поля или изменить формат вывода, все эти изменения можно выполнить на этапе обработки данных с помощью jq
, что делает его мощным инструментом для работы с JSON.