如何使用jq查找和替换多个字段值?

如何使用jq查找和替换多个字段值?

在以下 json 文件中,

{
  "email": "xxx",
  "pass": "yyy",
  "contact": [
    {
      "id": 111,
      "name": "AAA"
    }
  ],
  "lname": "YYY",
  "name": "AAA",
   "group": [
    {
      "name": "AAA",
      "lname": "YYY",
    }
  ],

我需要查找键“name”并将其值替换为“XXX”。哪个 jq 命令执行此操作?

答案1

jq 的赋值操作可以同时在任意多个位置执行更新,并且是针对这种情况而设计的。您可以使用

jq '(.. | .name?) |= "XXXX"'

找到任意位置的每个名为“name”的字段,并一次性替换每个字段中的值与“XXXX”,并输出结果对象。

这只是..|.a?来自递归下降文档结合更新作业

它使用递归下降运算符..查找树中的每个值,然后从每个值中提取“名称”字段.name,抑制不匹配值的任何错误?,然后使用“XXXX”一次性更新所有这些位置的对象更新赋值运算符|=,并输出新对象。

无论文件结构是什么,这都可以工作,并更新各处的每个名称字段。


或者,如果文件始终具有此结构,并且它是您想要更改的那些特定“名称”字段,不仅仅是任何旧名称,您也可以将它们列出并分配给它们作为一个组:

jq '(.name, .contact[].name, .group[].name) |= "XXXX"'

这对以下内容执行相同的分配

  1. 顶级对象的“名称”字段;
  2. 的“名称”字段每一个“联系人”数组中的对象;和
  3. “group”数组中每个对象的“name”字段。

一气呵成。如果文件可能有,这特别有用其他名称字段位于不相关且您不想更改的地方。它只找到其中​​指定的三组位置并同时更新它们。


如果该值只是像这里一样的文字,那么简单的赋值与=也可以工作并为您节省一个字符:(..|.name?)="XXXX"- 如果您的值是基于整个顶级对象计算的,您也会需要这个。如果您想根据旧名称计算新名称,您可以需要使用|=.如果我不确定使用什么,|=通常在极端情况下会有更好的行为。

如果你有需要进行多次替换,你可以将它们连接在一起:

jq '(..|.name?) = "XXXX" | (..|.lname?) = "1234"'

将更新各处的“name”和“lname”字段,并输出整个更新后的对象一次。


其他一些可能有效的方法:

  • 您也可以非常明确地说明您正在选择的内容

      (..|objects|select(has("name"))).name |= "XXXX"`
    

它找到所有内容,然后仅找到对象,然后仅找到具有“名称”的对象,然后是这些对象上的名称字段,并执行与以前相同的更新。

  • 如果您正在运行 jq 的开发版本(不太可能),那么walk功能还可以完成以下工作:walk(.name?="XXXX").所有其他版本都将在最新发布的版本 1.5 上运行。

  • 另一种多重更新可能是

      jq '(..|select(has("name"))?) += {name: "XXXX", lname: "1234"}'
    

它找到了一切一个名称,然后在每个对象上设置“name”和“lname”算术更新分配*=+合并对象的行为

答案2

jq根据功能使用walk(需要最新版本):

jq 'walk(.name?="XXX")' file

如果您jq不支持该walk功能,只需将其定义为:

jq '
  # Apply f to composite entities recursively, and to atoms
  def walk(f):
    . as $in
    | if type == "object" then
       reduce keys[] as $key
         ( {}; . + { ($key):  ($in[$key] | walk(f)) } ) | f
    elif type == "array" then map( walk(f) ) | f
    else f
    end;
  walk(.name?="XXX")
' file

学分:https://github.com/stedolan/jq/issues/963

答案3

或者,jtc基于的解决方案:

bash $ jtc -w'<name>l+0' -u'"XXX"' your.json 
{
   "contact": [
      {
         "id": 111,
         "name": "XXX"
      }
   ],
   "email": "xxx",
   "group": [
      {
         "lname": "YYY",
         "name": "XXX"
      }
   ],
   "lname": "YYY",
   "name": "XXX",
   "pass": "yyy"
}
bash $ 

相关内容