如何在 macOS/Linux bash 中验证 jq 1.5 中的查询?



我正在尽我最大的努力弄清楚如何告诉我的一个脚本的用户他们传递了一个jq 1.5无效的查询。

下面是一个简单的示例 JSON:

{ "foo": { "bar":"baz" } } 

我希望能够在用户提供.foo.bax等查询时向用户显示错误消息,但当他们提供正确的查询(如.foo.bar)时,baz返回值。

我无法(或不知道如何)读取jq的返回值,因为我需要在子外壳中运行jq,即:

value="$(echo -e "${json}" | jq -r "${query}")"

当我给它一个无效的查询时,jq总是返回一个null字符串。 但我无法将其与可能包含在 JSON 文件中的null值区分开来,作为"property": "null".

看起来jq有各种功能,我可以使用它们,但我无法弄清楚我将如何使用它们。

那么有没有办法让jq来验证查询,我可以分辨出null"null"之间的区别?


更新

当我问这个问题时,我希望找到的是一个大致等同于"$(jq.validate("${query}") && echo "valid")"的语法,假设jq有一个validate()方法。

您可以在jq中使用标志将jq的退出代码传播到 shell,您可以在命令中使用该代码来查看它是否成功。

官方的jq文档为此提供了正确的选择,

-e/--退出状态:

如果最后一个输出值既不是false也不是null1最后一个输出值是falsenull,则jq的退出状态设置为0,如果没有产生任何有效结果,则4。通常,如果存在任何使用问题或系统错误,3如果存在jq程序编译错误,或者如果jq程序运行,0jq会退出2

您可以看到它的用法如下:-

jsonStr='{"foo": 42, "bar": "less interesting data"}'
jq -er '.foo' <<<"$jsonStr"
42
echo $?
0

现在对于失败案例,

jq -er '.foo1' <<<"$jsonStr"
null
echo $?
1

请记住,如果您不设置-e标志,则上述情况是不可能的,因为请参阅上述子句的最后一行

0jq程序是否运行

因此,除非您设置-e标志,否则错误代码不会传播到 shell。

(或者)使用 if 子句的更有意义的 shell 构造是执行以下操作,

jsonStr='{"foo": 42, "bar": "less interesting data"}'
if jq -er '.foo' <<<"$jsonStr" > /dev/null; then
printf "string contained foon"
fi

对于失败的情况,

if jq -er '.foo1' <<<"$jsonStr" > /dev/null; then
printf "string contained foon"
else
printf "string does not contain foon"
fi 

如果您仔细观察,将转到故障情况的else部分,这是您的意图。如果未设置-e标志,则仍会0失败案例退出代码,并且会满足真实条件。

>/dev/null部分只是为了抑制命令jq生成到空流stdout

另请注意,-e仅从 jq-1.4 开始引入。

请注意,如果使用-e选项,则 JSON 值false也会触发错误条件。

如果目标是能够区分 JSON 值null和 JSON 字符串"null", 那么请注意,这也可以通过不使用"-r"选项来完成。

如果你真的需要结果,好像是由jq -r生成的,那么考虑首先使用jq "$query"和 然后使用 -r 选项再次调用 jq。

我(作为一个jq菜鸟)会像这样验证它:

query()(
local q=$1
local json='{"foo":"bar"}'
local value=$(jq -r "if($q) then $q else empty end" <<<"$json" 2>/dev/null)
if ! test -n "$value"; then
echo "You've done it all wrong"
return 1
fi >&2
echo "$value"
)

在行动中: $ query foo You've done it all wrong $ query .foo bar $ echo $? 0 $ query .foo1 You've done it all wrong $ echo $? 1

最新更新