验证 jq 和 bash 是否存在 json 字段?

verify that a json field exists with jq and bash?

我有一个脚本使用 jq 来解析 json 字符串 MESSAGE(从另一个应用程序读取)。同时 json 发生了变化,一个字段被拆分为 2 个字段:file_path 现在拆分为 folderfile。脚本正在读取 file_path,现在 folder 可能不存在,因此为了创建文件路径,我必须验证该字段是否存在。我在网上搜索了一段时间,设法做到了:

echo $(echo $MESSAGE | jq .folder -r)$'/'$(echo $MESSAGE | jq .file -r)

if [ $MESSAGE | jq 'has(".folder")' -r  ]
then
        echo $(echo $MESSAGE | jq .folder -r)$'/'$(echo $MESSAGE | jq .file -r)
else
        echo $(echo $MESSAGE | jq .file -r)
fi

其中 MESSAGE='{"folder":"FLDR","file":"fl"}'MESSAGE='{"file":"fl"}'

如果文件夹字段不存在,第一行打印 FLDR/flnull/fl。所以我想创建一个 if 来验证文件夹字段是否存在,但似乎我做错了,无法找出问题所在。输出是

bash: [: missing `]'
jq: ]: No such file or directory
null/fl

我会在 jq 过滤器中完成所有操作:

echo "$MESSAGE" | jq -r '[ .folder, .file ] | join("/")'

如果你想用 bash 来做(或者想在 bash 中学习如何做这类事情),两点:

  • Shell 变量在使用时几乎总是应该被引用(即 "$MESSAGE" 而不是 $MESSAGE)。如果 JSON 中的某个字符串包含 shell 元字符(例如 *)而您忘记这样做,您将 运行 陷入有趣的问题;该字符串将受到 shell 扩展(并且 * 将扩展为当前工作目录中的文件列表)。
  • A shell if 接受命令作为条件,并根据该命令的退出状态决定分支位置(如果退出状态为 0,则为真,否则为假)。您尝试使用的 [ 只是一个命令([=20= 的别名],请参阅 man test)并且没有任何特殊意义。

因此,目标是构造一个命令,如果 JSON 对象具有 folder 属性,则该命令以 0 退出,否则为非零。 jq 有一个 -e 选项,如果最后的输出值不是 falsenull 并且非零,则它会变成 return 0,所以我们可以写

if echo "$MESSAGE" | jq -e 'has("folder")' > /dev/null; then
    echo "$MESSAGE" | jq -r '.folder + "/" + .file'
else
    echo "$MESSAGE" | jq -r .file
fi

> /dev/null 位将输出从 jq 重定向到 /dev/null(它被忽略),这样我们就不会在控制台上看到它。