Добавить переменную bash как ключ и значение JSON в объект

Добавить переменную bash как ключ и значение JSON в объект

У меня есть JSON-массив объектов, подобных этому.

[
  {
    "id" : "tmp1387816934708382026",
    "owner" : "john",
    "x11-display" : ":5",
    "x11-authority" : "/run/user/john/dcv/tmp1387816934708382026.xauth",
    "num-of-connections" : 1,
    "creation-time" : "2019-05-14T14:12:14.989287Z",
    "last-disconnection-time" : "2019-05-31T18:58:42.851223Z"
  },
  {
    "id" : "tmp4241942441012516520",
    "owner" : "mike",
    "x11-display" : ":10",
    "x11-authority" : "/run/user/mike/dcv/tmp4241942441012516520.xauth",
    "num-of-connections" : 0,
    "creation-time" : "2019-05-17T16:23:05.891531Z",
    "last-disconnection-time" : "2019-05-19T11:23:30.844797Z"
  }
]

Мне нужно добавить ключ с именем days-idleи значением к каждому объекту, который вычисляется внутри моего скрипта bash. Это то, что я ищу в каждом объекте JSON.

{
    "id" : "tmp1387816934708382026",
    "owner" : "mike",
    "x11-display" : ":5",
    "x11-authority" : "/run/user/mike/dcv/tmp1387816934708382026.xauth",
    "num-of-connections" : 1,
    "creation-time" : "2019-05-14T14:12:14.989287Z",
    "last-disconnection-time" : "2019-05-31T18:58:42.851223Z",
    "days-idle" : "$daysIdle"
  }

Я знаю, что можно добавить ключ с помощью , jqно не уверен, как добавить пару ключ-значение, где значением является переменная bash.

решение1

Предположим, вы хотите добавить новый ключ к элементу с определенным .idзначением $id:

jq --arg id "$id" --arg idle "$daysIdle" \
    '( .[] | select(.id == $id)."days-idle" ) |= $idle' file

Это выбирает элемент массива, который .idмы хотим изменить, а затем добавляет (на самом делеобновления) ."days-idle"ключ к этому элементу с определенным значением, которое мы хотим ему присвоить.

Если ."days-idle"должно быть время между ."last-disconnection-time"меткой времени исейчас, то вы можете обновить все элементы в JSON следующим образом:

jq 'def dayssince: ((now - (sub("[.].*"; "Z") | fromdate))/86400) | round;
    map(. += { "days-idle": (."last-disconnection-time" | dayssince) })' file

Вызов sub()обрежет временную метку до точки и заменит ее конец на Z. Это связано с fromdateнекоторыми ограничениями в типе временных меток, которые он может анализировать, и не обрабатывает точность исходной строки временной метки в доли секунды.

Я решил поместить фактический расчет количества дней с момента создания временной метки в jqфункцию с именем dayssince, просто чтобы сохранить аккуратность кода.

Итоговый JSON (при запуске 28 июня 2021 г.):

[
  {
    "id": "tmp1387816934708382026",
    "owner": "john",
    "x11-display": ":5",
    "x11-authority": "/run/user/john/dcv/tmp1387816934708382026.xauth",
    "num-of-connections": 1,
    "creation-time": "2019-05-14T14:12:14.989287Z",
    "last-disconnection-time": "2019-05-31T18:58:42.851223Z",
    "days-idle": 759
  },
  {
    "id": "tmp4241942441012516520",
    "owner": "mike",
    "x11-display": ":10",
    "x11-authority": "/run/user/mike/dcv/tmp4241942441012516520.xauth",
    "num-of-connections": 0,
    "creation-time": "2019-05-17T16:23:05.891531Z",
    "last-disconnection-time": "2019-05-19T11:23:30.844797Z",
    "days-idle": 771
  }
]

решение2

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

bash$ object='[
  {
    "id" : "tmp1387816934708382026",
    "owner" : "john",
    "x11-display" : ":5",
    "x11-authority" : "/run/user/john/dcv/tmp1387816934708382026.xauth",
    "num-of-connections" : 1,
    "creation-time" : "2019-05-14T14:12:14.989287Z",
    "last-disconnection-time" : "2019-05-31T18:58:42.851223Z"
  },
  {
    "id" : "tmp4241942441012516520",
    "owner" : "mike",
    "x11-display" : ":10",
    "x11-authority" : "/run/user/mike/dcv/tmp4241942441012516520.xauth",
    "num-of-connections" : 0,
    "creation-time" : "2019-05-17T16:23:05.891531Z",
    "last-disconnection-time" : "2019-05-19T11:23:30.844797Z"
  }
]'

Далее я предположу, что $daysIdleэто также переменная и содержит число:

bash$ daysIdle=3

Теперь мы можем выполнить эхо- $objectзапрос jq, чтобы добавить эту переменную.

bash$ echo "$object" | jq --arg daysIdle "$daysIdle" '.[]."days-idle" = ($daysIdle | tonumber)'

Несколько важных замечаний по этому поводу. Если объекты на самом деле находятся в файле или поступают из какого-то другого потока, например cURL, просто замените echo $objectто, что подходит. Во-вторых, я предполагаю, что вы хотите получить его как число JSON, а не как строку, которая --argобычно создается, поэтому у меня есть фильтр, чтобы это исправить. Наконец, обратите внимание, что я использую опцию --argto jqдля передачи значения. Это намного лучше и безопаснее, чем пытаться встроить значение в саму строку фильтра JSON, и не вызовет в ней синтаксической ошибки. Он выдаст ошибку, если не сможет преобразовать его в число, но не позволит выполнить произвольную инъекцию в строку фильтра. С учетом сказанного давайте посмотрим на вывод:

[
  {
    "id": "tmp1387816934708382026",
    "owner": "john",
    "x11-display": ":5",
    "x11-authority": "/run/user/john/dcv/tmp1387816934708382026.xauth",
    "num-of-connections": 1,
    "creation-time": "2019-05-14T14:12:14.989287Z",
    "last-disconnection-time": "2019-05-31T18:58:42.851223Z",
    "days-idle": 3
  },
  {
    "id": "tmp4241942441012516520",
    "owner": "mike",
    "x11-display": ":10",
    "x11-authority": "/run/user/mike/dcv/tmp4241942441012516520.xauth",
    "num-of-connections": 0,
    "creation-time": "2019-05-17T16:23:05.891531Z",
    "last-disconnection-time": "2019-05-19T11:23:30.844797Z",
    "days-idle": 3
  }
]

Связанный контент