使用 jq --arg 传递的数字参数与 == 不匹配的数据

Numeric argument passed with jq --arg not matching data with ==

这是来自我的 curl 的 JSON 响应示例:

{
  "success": true,
  "message": "jobStatus",
  "jobStatus": [
    {
      "ID": 9,
      "status": "Successful"
    },
    {
      "ID": 2,
      "status": "Successful"
    },
   {
      "ID": 99,
      "status": "Failed"
    }
  ]
}

我想查看 ID=2 的状态。这是我试过的命令:

cat test.txt|jq --arg v "2" '.jobStatus[]|select(.ID == $v)|.status'

回复:有none

我尝试了不带引号的值 2,但仍然没有结果。

相比之下,如果我尝试使用 文字 2 命令,它会起作用:

cat test.txt | jq '.jobStatus[]|select(.ID == 2)|.status'

回复:

"Successful"

我卡住了。谁能帮我找出问题所在?

jq 是 data-type-aware:

  • .ID,如 JSON 输入中所定义,是一个 number ,

  • 但是通过 --arg 传递的任何 command-line 参数 (例如这里的 v)总是 string(不管你是否引用该值),

因此,为了比较它们,您必须使用显式类型转换,例如 tonumber/1:

jq --arg v '2' '.jobStatus[] | select(.ID == ($v | tonumber)) | .status' test.txt

鉴于您只在此处传递 标量 参数,以下解决方案使用 --argjson (jq v1.5+) 是一个有点矫枉过正,但它是 显式类型转换 的替代方法,因为 在其中传递 JSON 参数效果通过 typed data:

jq --argjson v '{ "ID": 2 }' '.jobStatus[] | select(.ID == $v.ID) | .status' test.txt

证明 even --argjson v 2 有效 (在这种情况下与 $v 比较直接有效),这当然是 简洁解决方案,但可能需要解释:

  • 即使 2 可能 看起来 不像 JSON,它是:它是一个有效的 JSON 文本包含类型为 number 的单个 value(参见 json.org)。

    • 具体来说,2 是一个 unquoted 标记,以 digit 开头,这使得它成为JSON 上下文中的数字(JSON string 等效值是 "2",它来自shell 必须作为 '"2"' 传递——注意嵌入的双引号)。
  • 因此 jq--argjson -v 2 解释为 数字 ,并且比较 .ID == $v 按预期工作(请注意这同样适用于 --argjson -v '2' / --argjson -v "2",其中 shell 在 jq 看到值之前删除了引号。
    相比之下,您使用 --arg 传递的任何内容始终是一个 string 值,该值用于 as-is.

  • 换句话说:--argjson,其目的是接受任意JSON文本作为字符串(如上例中的'{ "ID": 2 }'),也可以用于传递 number-string 标量 以强制将其解释为数字。
    同样的技术也适用于布尔字符串 truefalse.


peak 致敬。

假设您要检查 JSON 值 2,您可以做出选择 - 将 --arg 的参数转换为数字,或将 --argjson 与数字参数。这些备选方案如下所示:

jq --arg v 2 '.jobStatus[] | select(.ID == ($v|tonumber) | .status' 

jq --argjson v 2 '.jobStatus[] | select(.ID == $v) | .status'

请注意 --argjson 需要相对较新版本的 jq。

当然,如果你想 "normalize" .ID 以便它始终被视为一个字符串,你可以这样写:

jq --arg v 2 '.jobStatus[] | select((.ID|tostring) == $v) | .status'