dec*_*her 5 text-processing json jq
[
{
"name": "user1",
"status": "off"
},
{
"name": "user2",
"status": "off"
},
{
"name": "user3",
"status": "on"
}
]
Run Code Online (Sandbox Code Playgroud)
我想知道如何递归搜索 JSON 文件中的值status,例如 ,off并获取name状态为 的所有值off。
另外,如何更改user1和user2的值on?
我正在使用jq和bash。
Kus*_*nda 12
要将表达式应用于数组的所有元素并获取更改后的数组,请使用map(expression)。
提取所有具有off状态的条目:
$ jq 'map(select(.status == "off"))' file
[
{
"name": "user1",
"status": "off"
},
{
"name": "user2",
"status": "off"
}
]
Run Code Online (Sandbox Code Playgroud)
映射将通过仅提取(选择)为true的select(.status == "off")元素来更改数组。.status == "off"
仅从上面提取解码后的名称:
$ jq -r 'map(select(.status == "off"))[].name' file
user1
user2
Run Code Online (Sandbox Code Playgroud)
[].name在上一个表达式的末尾添加将首先将数组扩展为一组单独的条目(就是这样[]做的),然后.name从每个条目中提取值。
你也可以使用
jq -r 'map(select(.status == "off").name)[]' file
Run Code Online (Sandbox Code Playgroud)
...它创建一个名称数组,然后从中提取所有元素。
on将所有具有状态的条目的状态设置为off:
$ jq 'map(select(.status == "off").status = "on")' file
[
{
"name": "user1",
"status": "on"
},
{
"name": "user2",
"status": "on"
},
{
"name": "user3",
"status": "on"
}
]
Run Code Online (Sandbox Code Playgroud)
通过映射,我们通过将任何状态为 的元素的select(.status == "off").status = "on"状态设置为 来修改数组。onoff
on将基于显式名称的条目的状态设置为:
$ jq 'map(select(.name == "user1" or .name == "user2").status = "on")' file
[
{
"name": "user1",
"status": "on"
},
{
"name": "user2",
"status": "on"
},
{
"name": "user3",
"status": "on"
}
]
Run Code Online (Sandbox Code Playgroud)
同样的事情,但不要在表达式中硬编码名称。相反,将它们作为命令行末尾的列表提供(请注意,--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"
}
]
Run Code Online (Sandbox Code Playgroud)
给定的名称列表--args可以在名为 的数组中找到$ARGS.positional。
如果出现在集合中,则该IN(a; b)事物返回true。我们使用作为搜索集,它是命令行上给出的名称集。这意味着我们在这里将仅提取名称出现在命令行列表中的元素,并且这些元素的状态将设置为。ab$ARGS.positional[]select()on
请注意,它IN(a; b)与类似名称的不同in(a),如果给定值作为对象或数组中的键或索引出现,则返回truea。
将所有条目的状态设置为on:
$ jq 'map(.status = "on")' file
[
{
"name": "user1",
"status": "on"
},
{
"name": "user2",
"status": "on"
},
{
"name": "user3",
"status": "on"
}
]
Run Code Online (Sandbox Code Playgroud)
评论中的后续问题:
如果我想像这样匹配
NOT IN(a, b),那么呢?显然,我问的是我是否传递像这样的值user1,它会关闭除 之外的所有内容user1。我怎样才能这样做呢?
以下使用显式语句将给定名称的if状态更改为,并将所有其他名称的状态更改为:onoff
jq '
map(
if IN(.name; $ARGS.positional[]) then
.status = "on"
else
.status = "off"
end
)' file --args user1
Run Code Online (Sandbox Code Playgroud)
或者,在单行布局中:
jq 'map(if IN(.name; $ARGS.positional[]) then .status = "on" else .status = "off" end)' file --args user1
Run Code Online (Sandbox Code Playgroud)
如果我将后续操作解释为不想更改给定名称的状态,无论它们的状态是什么,而是将所有其他状态更改为off. 在这种情况下,我们可以否定先前变体中使用的条件:
jq 'map(select(IN(.name; $ARGS.positional[]) | not).status = "off")' file --args user1
Run Code Online (Sandbox Code Playgroud)
| not注意后面添加的IN(...; ...)。
当然,您if也可以在上述大多数变体中使用语句,但我喜欢select()在可以的情况下使用。