我有一个像这样的 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(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
现在,我们可以回显$object
throughjq
添加该变量。
bash$ echo "$object" | jq --arg daysIdle "$daysIdle" '.[]."days-idle" = ($daysIdle | tonumber)'
关于这一点的一些重要说明。如果对象实际上位于文件中或来自其他流(例如 cURL),则只需替换echo $object
适当的内容即可。其次,我假设您希望它作为 JSON 数字而不是--arg
通常创建的字符串,因此我在其中有一个过滤器来解决这个问题。最后,请注意,我使用--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
}
]