如何使用 jq 检查 JSON 中的值并更改其他键?

如何使用 jq 检查 JSON 中的值并更改其他键?
[
    {
        "name": "user1",
        "status": "off"
    },
    {
        "name": "user2",
        "status": "off"
    },
    {
        "name": "user3",
        "status": "on"
    }
]

我想知道如何递归搜索 JSON 文件中的值status,例如 ,off并获取name状态为 的所有值off

另外,如何更改user1user2的值on

我正在使用jqbash

答案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"状态设置为 来修改数组。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"
  }
]

同样的事情,但不要在表达式中硬编码名称。相反,将它们作为命令行末尾的列表提供(请注意--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状态更改为 ,并将所有其他名称的状态更改为:onoff

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()在可以的情况下使用。

相关内容