所以我有这个:
(
set -eo pipefail;
{
set -eo pipefail;
file_path="$(echo "$i" | jq -r '.file_path')"
if [[ -n "$file_path" ]]; then
echo "$i" > "$file_path";
fi
} || {
# never seems to reach here
echo "!!! json parse error: 'xxxx'";
}
)
我希望在我的终端中出现这样的情况:
!!! json parse error: 'xxxx'
jq
但我的终端中不断出现此错误:
parse error: Invalid numeric literal at line 2, column 0
不知道为什么通常对我有用的“catch block”在这里不起作用
答案1
中的shellpipefail
选项bash
导致管道的退出状态为最右侧命令的退出状态,且退出状态非零(如果所有命令成功退出,则退出状态为零)。在您的情况下,您拥有的唯一管道是echo
+jq
管道,并且echo
不太可能失败,从而使该pipefail
选项变得多余。
errexit
( ) shell选项set -e
导致 shell 在第一个返回非零退出状态的命令处终止,除非该命令是 AND-OR 列表的一部分,例如代码中的列表。
激发!!! json parse error: 'xxxx'
代码输出的唯一方法是通过if
复合命令返回非零退出状态,如果 shell 无法写入$file_path
.
就我个人而言,我会避开这两个 shell 选项,除非您遇到绝对需要它们的情况(我在自己的 shell 脚本中还没有看到过其中一种情况)。
jq
如果解析生成一些非空值,您似乎希望将 JSON 文档写入文件(由 的输出给出),并在解析失败时输出错误消息。
确定解析是否顺利可能最简单的方法是jq
直接在if
语句中使用退出状态。
在这里,我们另外捕获错误输出jq
并在我们自己的错误报告中使用它:
if filepath=$( jq -r '.file_path' <<<"$json_document" 2>&1 )
then
# Parsing went ok.
if [ -n "$filepath" ]; then
# "$filepath" is non-empty.
printf '%s\n' "$json_document" >"$filepath"
fi
else
# Parsing failed.
printf 'ERROR: "%s"\n' "$filepath" >&2
fi
但老实说,我只是让它jq
自己进行错误报告,而根本不参与其中,这简化了代码:
if filepath=$( jq -r '.file_path' <<<"$json_document" ) && [ -n "$filepath" ]
then
# Parsing went ok, and "$filepath" is non-empty.
printf '%s\n' "$json_document" >"$filepath"
fi
或者,让jq
我们告诉我们该值为空,这将消除测试-n
:
if filepath=$( jq -r -e '.file_path' <<<"$json_document" )
then
# Parsing went ok, and "$filepath" is non-empty (and not null or false).
printf '%s\n' "$json_document" >"$filepath"
fi
对于-e
,jq
将在出现错误时返回非零退出状态(像往常一样),但如果最终表达式产生空结果,null
, 或也会返回false
。
答案2
我真的不明白为什么您会期望看到该消息。您正在测试一组命令的退出代码,这意味着您正在测试该组中最后一个命令的退出代码。在您的情况下,最后一个命令是if
或者,如果是if
true,则echo
:
if [[ -n "$file_path" ]]; then
echo is n
fi
由于这是最后运行的命令,那是您|| echo "!!! json parse error: 'xxxx'"
测试的对象,并且由于执行的if
和echo
if 都会返回 true,因此您永远不会进入“catch 块”。
如果您希望由于该选项而执行此pipefail
操作,则该操作将不起作用,因为这不是管道:
$ { false | true; } || echo FAILED
$ set -o pipefail
$ { false | true; } || echo FAILED
FAILED
但是如果我现在在管道之后添加另一个无失败命令:
$ { false | true; true;} || echo FAILED
$
这就是你的脚本中的内容。