我想仅在前一个命令成功时才按顺序运行一系列命令。根据Shell 脚本:使用“set -e”进行错误处理的危险:
建议通过将一系列带有“&&”的命令串在一起来进行自己的错误检查,如下所示:
mkdir abc && cd abc && do_something_else && last_thing || { echo error >&2; exit 1; }
在某些命令之间必须存在一些脚本逻辑(例如循环或复杂条件)的情况下,将状态捕获到变量然后再次使用该变量以确保仅执行其他命令的惯用方法是什么之前的命令是否成功?
就像是:
mkdir abc
status=$?
... # do stuff (which might alter $?)
$status && cd abc
status=$?
... # do more stuff
$status && do_something_else
status=$?
... # do even more
$status && last_thing
status=$?
... # do final stuff
$status || { echo error >&2; exit 1; }
答案1
OP 自己提供的答案中的一个稍微干净(在我看来)的版本可能是:
bail() {
return=${1-1} # if no parameters sent, default to exit code 1
shift
echo "$@" 1>&2
exit $return
}
if mkdir abc; then
do_stuff
else
bail 1 "Unable to create directory"
fi
if cd abc; then
do_stuff
else
bail 2 "Unable to enter directory"
fi
# et cetera
关键是为每个失败案例提供自己的退出代码,并且此构造还允许您else
在触发之前在每个子句中进行自己的失败案例管理bail()
。
答案2
当我写下这个问题时,我意识到一种可能的解决方案是:
mkdir abc || { echo error >&2; exit 1; }
... # do stuff (which might alter $?)
cd abc || { echo error >&2; exit 1; }
... # do more stuff
do_something_else || { echo error >&2; exit 1; }
... # do even more
last_thing || { echo error >&2; exit 1; }
... # do final stuff
在这种情况下,$status
甚至不需要变量,并且仅当前面的命令成功时才会执行命令。而且,我还意识到,这是die "error message"
函数可以派上用场的地方,它可以回显错误消息并以错误代码退出。
更新
和die
, 这将是:
die() { echo "$*" >&2; exit 1; }
mkdir abc || die "error"
... # do stuff
cd abc || die "error"
... # do more stuff
do_something_else || die "error"
... # do even more
last_thing || die "error"
... # do final stuff