我问过类似的问题过去但我很难适应这个问题的解决方案。
我有以下 json 数组:
$ jq <<<"$json"
[
{
"id": "node1"
},
{
"id": "node2"
},
{
"id": "node3"
}
]
我想向每个节点添加一个键/值或修改它(如果它已经存在)。我可以这样做:
$ jq '.[] | select(.id == "node2") += {status: "fail"}' <<<"$json"
{
"id": "node1"
}
{
"id": "node2",
"status": "fail"
}
{
"id": "node3"
}
但请注意,外部数组消失了,因此当我尝试在脚本中实现此解决方案时,它失败了。
#!/usr/bin/env bash
[[ $DEBUG == true ]] && set -x
nodes=(node1 node2 node3)
json='[{"id": "node1"},{"id": "node2"},{"id": "node3"}]'
for node in "${nodes[@]}"; do
if [[ $node == node2 ]]; then
status=fail
else
status=pass
fi
json=$(jq --arg status "$status" --arg node "$node" '.[] | select(.id == $node) += {status: $status}' <<<"$json")
done
错误:
$ ./script.sh
jq: error (at <stdin>:4): Cannot index string with string "id"
jq: error (at <stdin>:7): Cannot index string with string "id"
jq: error (at <stdin>:10): Cannot index string with string "id"
有没有办法可以修改这些 json 对象,同时保留整体结构?
答案1
.[]
一旦您从with中选择了一个元素select()
,这就是您剩下的唯一数据以及最后将输出的内容。
相反,使用map()
对顶级数组的每个元素应用(可能的)修改:
$ jq --arg id node2 --arg status fail 'map(select(.id == $id) += { status: $status } )' file
[
{
"id": "node1"
},
{
"id": "node2",
"status": "fail"
},
{
"id": "node3"
}
]
或者可能更整洁,用更少的大括号,
$ jq --arg id node2 --arg status fail 'map(select(.id == $id).status = $status)' file
[
{
"id": "node1"
},
{
"id": "node2",
"status": "fail"
},
{
"id": "node3"
}
]
复制 shell 循环jq
以避免多次调用jq
:
$ jq --arg failnode node2 'map(.status = if .id == $failnode then "fail" else "pass" end)' file
[
{
"id": "node1",
"status": "pass"
},
{
"id": "node2",
"status": "fail"
},
{
"id": "node3",
"status": "pass"
}
]
--args
或者,使多个节点失败,并在命令行上列出每个失败的节点(请注意最后的非正统但必要的放置):
$ jq 'map(.status = if (.id|IN($ARGS.positional[])) then "fail" else "pass" end)' file --args node1 node2
[
{
"id": "node1",
"status": "fail"
},
{
"id": "node2",
"status": "fail"
},
{
"id": "node3",
"status": "pass"
}
]