![如何使用 jq 检查 JSON 中的值并更改其他键?](https://linux22.com/image/211429/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20jq%20%E6%A3%80%E6%9F%A5%20JSON%20%E4%B8%AD%E7%9A%84%E5%80%BC%E5%B9%B6%E6%9B%B4%E6%94%B9%E5%85%B6%E4%BB%96%E9%94%AE%EF%BC%9F.png)
[
{
"name": "user1",
"status": "off"
},
{
"name": "user2",
"status": "off"
},
{
"name": "user3",
"status": "on"
}
]
我想知道如何递归搜索 JSON 文件中的值status
,例如 ,off
并获取name
状态为 的所有值off
。
另外,如何更改user1
和user2
的值on
?
我正在使用jq
和bash
。
答案1
要将表达式应用于数组的所有元素并获取更改后的数组,请使用map(expression)
。
提取所有具有off
状态的条目:
$ jq 'map(select(.status == "off"))' file
[
{
"name": "user1",
"status": "off"
},
{
"name": "user2",
"status": "off"
}
]
映射select(.status == "off")
将通过仅提取(选择)以下元素来更改数组.status == "off"
:真的。
仅从上面提取解码后的名称:
$ jq -r 'map(select(.status == "off"))[].name' file
user1
user2
在上一个表达式的末尾添加[].name
将首先将数组扩展为一组单独的条目(就是这样[]
做的),然后.name
从每个条目中提取值。
你也可以使用
jq -r 'map(select(.status == "off").name)[]' file
...它创建一个名称数组,然后从中提取所有元素。
on
将所有具有状态的条目的状态设置为off
:
$ jq 'map(select(.status == "off").status = "on")' file
[
{
"name": "user1",
"status": "on"
},
{
"name": "user2",
"status": "on"
},
{
"name": "user3",
"status": "on"
}
]
通过映射,我们通过将任何状态为 的元素的select(.status == "off").status = "on"
状态设置为 来修改数组。on
off
on
将基于显式名称的条目的状态设置为:
$ jq 'map(select(.name == "user1" or .name == "user2").status = "on")' file
[
{
"name": "user1",
"status": "on"
},
{
"name": "user2",
"status": "on"
},
{
"name": "user3",
"status": "on"
}
]
同样的事情,但不要在表达式中硬编码名称。相反,将它们作为命令行末尾的列表提供(请注意--args
,名称列表必须是命令行上的最后一件事):
$ jq 'map(select(IN(.name; $ARGS.positional[])).status = "on")' file --args user1 user2
[
{
"name": "user1",
"status": "on"
},
{
"name": "user2",
"status": "on"
},
{
"name": "user3",
"status": "on"
}
]
给定的名称列表--args
可以在名为 的数组中找到$ARGS.positional
。
东西IN(a; b)
回来了真的如果a
出现在集合中b
。我们使用$ARGS.positional[]
作为搜索集,它是命令行上给出的名称集。这意味着我们select()
在这里将仅提取名称出现在命令行列表中的元素,并且这些元素的状态将设置为on
。
请注意,IN(a; b)
与类似名称的不同in(a)
,后者返回真的如果给定值作为对象或数组中的键或索引出现a
。
环境全部条目的状态为on
:
$ jq 'map(.status = "on")' file
[
{
"name": "user1",
"status": "on"
},
{
"name": "user2",
"status": "on"
},
{
"name": "user3",
"status": "on"
}
]
评论中的后续问题:
如果我想像这样匹配
NOT IN(a, b)
,那么呢?显然,我问的是我是否传递像这样的值user1
,它会关闭除 之外的所有内容user1
。我怎样才能这样做呢?
以下使用显式语句将给定名称的if
状态更改为 ,并将所有其他名称的状态更改为:on
off
jq '
map(
if IN(.name; $ARGS.positional[]) then
.status = "on"
else
.status = "off"
end
)' file --args user1
或者,在单行布局中:
jq 'map(if IN(.name; $ARGS.positional[]) then .status = "on" else .status = "off" end)' file --args user1
如果我将后续解释为不是想要更改给定名称的状态,无论其状态是什么,但要将所有其他状态更改为off
.在这种情况下,我们可以否定先前变体中使用的条件:
jq 'map(select(IN(.name; $ARGS.positional[]) | not).status = "off")' file --args user1
| not
注意后面添加的IN(...; ...)
。
当然,您if
也可以在上述大多数变体中使用语句,但我喜欢select()
在可以的情况下使用。