Эмуляция gron с использованием jq

Вопрос или проблема

Недавно я открыл для себя 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'

Объяснение работы скрипта:

  1. to_entries[]: Эта функция преобразует входной объект в массив объектов с двумя полями: key и value. Каждый объект в массиве будет представлять собой “запись” исходного JSON.

  2. [.key, .value.remaining]: Здесь мы создаем новый массив, который содержит ключ и значение remaining из соответствующей записи.

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

Оцените материал
Добавить комментарий

Капча загружается...