次のようなオブジェクトの 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"
}
]
bash スクリプト内で計算される各オブジェクトに、値を持つ名前のキーを追加する必要がありますdays-idle
。これが、各 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
解析できるタイムスタンプの種類が少し制限されており、元のタイムスタンプ文字列の 1 秒未満の精度を処理できないためです。
コードを整理するために、タイムスタンプからの日数の実際の計算を というjq
関数として配置することにしました。dayssince
結果の JSON (2021 年 6 月 28 日に実行した場合):
[
{
"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
まず、Bash 変数に JSON オブジェクト配列があると仮定して、そこから始めましょう。
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
これで、 echo を実行してその変数に追加する$object
ことができます。jq
bash$ echo "$object" | jq --arg daysIdle "$daysIdle" '.[]."days-idle" = ($daysIdle | tonumber)'
これに関する重要な注意事項がいくつかあります。オブジェクトが実際にファイル内にある場合、または cURL などの他のストリームから取得されている場合は、echo $object
適切なものに置き換えてください。2 番目に、--arg
通常作成される文字列ではなく JSON 数値として必要なことを想定しているため、これを修正するためのフィルターがあります。最後に、値を渡す--arg
ためにオプションを使用していることに注意し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
}
]