【发布时间】:2020-03-11 13:40:18
【问题描述】:
假设我编写了如下代码:
if [ ${?} -ne 0 ]; then
exit ${?}
这能正常工作吗? 这是正确的“语法”吗?
【问题讨论】:
假设我编写了如下代码:
if [ ${?} -ne 0 ]; then
exit ${?}
这能正常工作吗? 这是正确的“语法”吗?
【问题讨论】:
您的if 语句中的[ 命令将在检查后设置$?。您需要在测试前保存原始退出状态。
some_command
es=$?
if [ "$es" -ne 0 ]; then
exit "$es"
fi
【讨论】:
语法正确,但$? 被if 语句中的[ ... ] 命令重置。根据定义,如果输入了if 块,那么[ ... ] 测试一定已经成功,并且$? 保证为0。
您需要将其保存在变量中。
result=$?
if ((result != 0)); then
exit "$result"
fi
另外,直接测试命令的结果比测试$? 更习惯。如果你这样做了,那么你就不会有$?改变的问题。
if command; then
echo success
else
exit # `exit` is equivalent to `exit $?`
fi
如果你不关心成功,那么你可以使用||:
command || exit
【讨论】:
command 返回(任何)非零状态,if ! command; then exit "$?"; fi(或if ! command; then exit; fi)将以状态 0 退出。 $? 获取否定状态的值。有关问题的解释和一些解决方案,请参阅Check exit code of a program called in a while loop。
如果您想在出错时退出并保留命令的 EXIT 代码,您可以启用 errexit 选项:
set -e
set -o errexit
见:help set | grep -F -- -e
-e 如果命令以非零状态退出,则立即退出。
errexit 与 -e
相同
或者,您可以trap ERR 信号并使用它以错误的返回码退出。
这将使您免于处理-e 选项的后果。
#!/usr/bin/env bash
err_handler() {
set -- $?
printf 'The error handler caught code #%d\n' "$1" >&2
exit "$1"
}
trap 'err_handler' ERR
create_error() {
[ $# -ne 1 ] && return 0
printf 'Create error #%d\n' "$1"
return "$1"
}
create_error "$@"
测试不同的错误:
for e in 1 0 2; do ./a.sh "$e" ;echo $?; done
Create error #1
The error handler caught code #1
1
Create error #0
0
Create error #2
The error handler caught code #2
2
【讨论】:
set -o errexit (set -e) 存在限制和困难。我很乐意与他们打交道,但很多人不喜欢。请参阅BashFAQ/105 (Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?) 以获得良好、平衡的信息。
trap添加了一个替代解决方案。
errtrace 以使ERR 陷阱触发所有将使用errexit 触发的东西。见What does set -o errtrace do in a shell script?。 ERR 陷阱的优点是处理程序可以打印有关错误上下文的有用信息。 (errexit 程序有时会莫名其妙地停止。)除此之外,ERR 陷阱与errexit 具有所有相同的限制和困难。需要格外小心。