更新字段时已知 jq 错误的解决方法

workaround for known jq error while updating fields

如果可能,我想将整个 json 中“字符串”类型的每个值更新为一个数字。 如果该值不能解析为数字,则应保留字符串。

我尝试使用 jq 解决此问题时遇到了 1.6 版的已知错误。

我不知道如何解决这个错误。 关于如何在没有 运行 这个已知错误的情况下解决任务的想法?

另请参阅:

示例输入

{
  "outer": {
    "inner": [
      {
        "foo": "foo",
        "bar": "11",
        "count": 12,
        "data": ["13", "14"]
      },
      {
        "foo": "foo",
        "bar": "15",
        "count": 16,
        "child": {
          "otherData": ["17", "18"]
        }
      }
    ]
  }
}

期望的输出

{
  "outer": {
    "inner": [
      {
        "foo": "foo",
        "bar": 11,
        "count": 12,
        "data": [13, 14]
      },
      {
        "foo": "foo",
        "bar": 15,
        "count": 16,
        "child": {
          "otherData": [17, 18]
        }
      }
    ]
  }
}

尝试 1 解决 - 无效

jq '(..| strings) |= try tonumber catch .'

输出

{
  "outer": {
    "inner": [
      {
        "foo": "Invalid literal at EOF at line 1, column 3 (while parsing 'foo')",
        "bar": {
          "__jq": 1
        },
        "count": 12,
        "data": [
          {
            "__jq": 2
          },
          {
            "__jq": 3
          }
        ]
      },
      {
        "foo": "Invalid literal at EOF at line 1, column 3 (while parsing 'foo')",
        "bar": {
          "__jq": 5
        },
        "count": 16,
        "child": {
          "otherData": [
            {
              "__jq": 6
            },
            {
              "__jq": 7
            }
          ]
        }
      }
    ]
  }
}

尝试 2 来解决 - 更糟

jq '(..| strings) |= tonumber? // .'

输出

{
  "outer": {
    "inner": [
      {
        "count": 12,
        "data": [
          "14"
        ]
      },
      {
        "count": 16,
        "child": {
          "otherData": [
            "18"
          ]
        }
      }
    ]
  }
}

按预期工作 - 但没有解决任务

该错误与结合 try catch 表达式的更新运算符有关

jq '(..| strings) |= (. + "___needs_update")'

{
  "outer": {
    "inner": [
      {
        "foo": "foo___needs_update",
        "bar": "11___needs_update",
        "count": 12,
        "data": [
          "13___needs_update",
          "14___needs_update"
        ]
      },
      {
        "foo": "foo___needs_update",
        "bar": "15___needs_update",
        "count": 16,
        "child": {
          "otherData": [
            "17___needs_update",
            "18___needs_update"
          ]
        }
      }
    ]
  }
}

walk 救援:

walk(if type == "string"
     then . as $in | try tonumber catch $in 
     else . end)

或者只是:

walk(if type == "string" then tonumber? // . else . end)

增强walk

如果您的 jq 没有 walk,或者您想要相对于(当前)内置版本的增强版本,请参阅 jq FAQ(搜索 def walk ).

这是 jq 1.5 或更高版本的无行走解决方案:

reduce paths(strings) as $p (.; 
  getpath($p) as $x | setpath($p; $x | tonumber? // $x))