题
我有一个执行许多命令的 shell 脚本。如果任何命令以非零退出代码退出,如何使 shell 脚本退出?
解决方案
在每个命令之后,可以在以下位置找到退出代码: $?
变量,所以你会得到类似的东西:
ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
您需要小心管道命令,因为 $?
只提供管道中最后一个元素的返回代码,因此在代码中:
ls -al file.ext | sed 's/^/xx: /"
如果文件不存在,则不会返回错误代码(因为 sed
管道的一部分实际上起作用,返回 0)。
这 bash
shell 实际上提供了一个可以在这种情况下提供帮助的数组,即 PIPESTATUS
. 。该数组为每个管道组件都有一个元素,您可以单独访问该元素,例如 ${PIPESTATUS[0]}
:
pax> false | true ; echo ${PIPESTATUS[0]}
1
请注意,这将为您提供以下结果 false
命令,而不是整个管道。您还可以根据需要处理整个列表:
pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1
如果您想从管道中获取最大的错误代码,您可以使用以下内容:
true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc
这经历了每一个 PIPESTATUS
依次元素,将其存储在 rc
如果它大于之前的 rc
价值。
其他提示
"set -e
“可能是最简单的方法。只需将其放在程序中的任何命令之前即可。
如果您在 bash 中不带任何参数调用 exit,它将返回最后一个命令的退出代码。与 OR 结合使用时,如果前一个命令失败,bash 应该只调用 exit。但我没有测试过这个。
command1 || exit; command2 || exit;
Bash 还将最后一个命令的退出代码存储在变量 $? 中。
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
http://cfaj.freeshell.org/shell/cus-faq-2.html#11
我如何获得退出代码
cmd1
在cmd1|cmd2
首先,请注意
cmd1
退出代码可能是非零的,但仍然并不意味着错误。例如,这种情况发生在cmd | head -1
您可能会观察到 141(或 ksh93 的 269)退出状态
cmd1
,但这是因为cmd
被 SIGPIPE 信号中断时head -1
读完一行后终止。了解管道元素的退出状态
cmd1 | cmd2 | cmd3
A。使用 zsh:
退出代码在 pipelinestatus 特殊数组中提供。
cmd1
退出代码位于$pipestatus[1]
,cmd3
退出代码在$pipestatus[3]
, , 以便$?
总是一样$pipestatus[-1]
.b.与bash:
退出代码在
PIPESTATUS
特殊阵列。cmd1
退出代码位于${PIPESTATUS[0]}
,cmd3
退出代码在${PIPESTATUS[2]}
, , 以便$?
总是一样${PIPESTATUS: -1}
....
欲了解更多详情,请参阅以下内容 关联.
对于bash:
# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;
#
# ... the rest of the script goes here
#
function catch_errors() {
# do whatever on errors
#
#
echo "script aborted, because of errors";
exit 0;
}
在 bash 中这很简单,只需用 && 将它们连接在一起:
command1 && command2 && command3
您还可以使用嵌套的 if 构造:
if command1
then
if command2
then
do_something
else
exit
fi
else
exit
fi
#
#------------------------------------------------------------------------------
# run a command on failure exit with message
# doPrintHelp: doRunCmdOrExit "$cmd"
# call by:
# set -e ; doRunCmdOrExit "$cmd" ; set +e
#------------------------------------------------------------------------------
doRunCmdOrExit(){
cmd="$@" ;
doLog "DEBUG running cmd or exit: \"$cmd\""
msg=$($cmd 2>&1)
export exit_code=$?
# if occured during the execution exit with error
error_msg="Failed to run the command:
\"$cmd\" with the output:
\"$msg\" !!!"
if [ $exit_code -ne 0 ] ; then
doLog "ERROR $msg"
doLog "FATAL $msg"
doExit "$exit_code" "$error_msg"
else
#if no errors occured just log the message
doLog "DEBUG : cmdoutput : \"$msg\""
doLog "INFO $msg"
fi
}
#eof func doRunCmdOrExit