我想知道为什么以下bash脚本会吞下错误消息。
#!/bin/sh
set -eu
LATEST=$(curl -s https://api.github.com/repos/dnote-io/cli/tags | grep -Eo '"name": "v\d*\.\d*\.\d*",' | head -n 1 | sed 's/[," ]//g' | cut -d ':' -f 2)
if [ -z $LATEST ]; then
echo "Error fetching latest version. Please try again."
exit 1
fi
....
基本上,脚本会抓取某些内容并将结果分配给变量LATEST
。但是当提取错误时,脚本不会打印来自curl
的实际错误消息。
关于如何不忽视错误的任何想法或建议?
答案 0 :(得分:3)
什么错误信息?
-s
,--silent
无声或安静模式。不要显示进度表或错误消息。使卷曲静音。
改为使用-sS
。
-S
,--show-error
当与-s
一起使用时,如果curl失败,则会使curl显示错误消息。
您的脚本中还有其他问题:
LATEST
中的空输出,但如果curl设法连接但连接在下载数据时被中断,则情况可能并非总是如此。
在bash中,但不是在sh中,您可以通过设置pipefail
选项来捕获管道左侧的故障。如果您想继续,请检查PIPESTATUS
,但请注意,您必须在命令替换中执行此操作。[ -z $LATEST ]
是错误的,因为LATEST
的值被拆分为以空格分隔的单词,这些单词被解释为通配符模式。如果值不包含任何特殊字符,它将起作用,但这很脆弱,尤其是因为您正在解析下载的内容。见Why does my shell script choke on whitespace or other special characters?
。始终在变量和命令替换周围使用双引号,除非您知道为什么需要将它们关闭。或者,在bash中但不在sh中,使用[[ … ]]
语法,它不需要双引号(比较运算符的右侧除外,如果你不想记住这些)例外,只是一直使用双引号。#!/bin/bash
set -eu
set -o pipefail
LATEST=$(curl -s https://api.github.com/repos/dnote-io/cli/tags | grep -Eo '"name": "v\d*\.\d*\.\d*",' | head -n 1 | sed 's/[," ]//g' | cut -d ':' -f 2)
if [ -z "$LATEST" ]; then
echo >&2 "Download from github successful, but extracting the version failed."
exit 1
fi
答案 1 :(得分:0)
这里有两个因素都有贡献。
您正在管道中运行curl
。 set -e
功能仅适用于管道中的最后一个命令;这就是shell的设计方式。
没有来自curl
的错误消息,因为您使用-s
运行它。
从命令中捕获输出并同时检查其退出状态很容易,但最终结果是shell变量。根据您的情况,这可能会也可能不会很麻烦。
if curlout=$(curl -s https://api.github.com/repos/dnote-io/cli/tags); then
# curl succeeded; *now* parse the result
latest="$(sed -n 's/.*"name": "\(v\[0-9]*\.\[0-9]*\.\[0-9]*\)",.*/!d;s//\1/;q' <<<"$curlout")"
else
rc=$?
echo "$0: curl failed: $rc" >&2
exit "$rc"
fi
我将您的长管道重构为单个sed
脚本,因为这样做相对容易。我仍然怀疑你能找到许多实际理解Perl正则表达式主义grep -E
的{{1}}实现,所以也许你的代码实际上并没有真正起作用。如果结果是JSON,那么正确的解决方案是使用适当的JSON解析器,例如\d
。
还要注意你的变量应该是小写的;大写变量通常保留供系统使用。
你的shebang说jq
所以你不能使用像#!/bin/sh
这样的Bash功能。也许你真的希望在shebang中pipefail
,所以你可以在你的脚本中使用Bash功能(无论如何,当你标记这个问题bash时)。