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

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

另外,如何更改user1user2的值on

我正在使用jqbash

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)

映射将通过仅提取(选择)为trueselect(.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()在可以的情况下使用。