使用 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 标量 以强制将其解释为数字。
同样的技术也适用于布尔字符串 true
和 false
.
向 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'
这是来自我的 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
--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 标量 以强制将其解释为数字。
同样的技术也适用于布尔字符串true
和false
.
向 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'