退出基于进程退出代码的Shell脚本
我有一个执行许多命令的shell脚本。 如果任何命令以非零退出代码退出,如何退出shell脚本?
在每个命令之后,可以在$?
find退出代码$?
variables,所以你会有这样的事情:
ls -al file.ext rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
你需要小心pipe道命令,因为$?
只给你pipe道中最后一个元素的返回代码,所以在代码中:
ls -al file.ext | sed 's/^/xx: /"
如果文件不存在,将不会返回错误代码(因为stream水线的sed
部分实际上工作,返回0)。
bash
shell实际上提供了一个数组,可以协助这种情况,即PIPESTATUS
。 这个数组对于每个pipe道组件都有一个元素,您可以像${PIPESTATUS[0]}
一样单独访问:
pax> false | true ; echo ${PIPESTATUS[0]} 1
请注意,这是得到你的false
命令的结果,而不是整个pipe道。 你也可以得到整个列表来处理你认为合适的:
pax> false | true | false; echo ${PIPESTATUS[*]} 1 0 1
如果你想从pipe道中获得最大的错误代码,你可以使用如下的东西:
true | true | false | true | false rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done echo $rc
如果它大于先前的rc
值,则依次通过每个PIPESTATUS
元素,将其存储在rc
。
如果你想使用$?,你需要在每个命令后检查它,因为$? 在每个命令退出后更新。 这意味着如果你执行一个pipe道,你将只能得到pipe道中最后一个进程的退出代码。
另一种方法是做到这一点:
set -e set -o pipefail
如果你把它放在shell脚本的顶部,它看起来像bash将为你照顾这个。 正如前面的海报所指出的那样,“set -e”会导致bash在任何简单的命令中出错并退出。 “set -o pipefail”会导致bash在pipe道中的任何命令上出错并退出。
看到这里或这里多一点关于这个问题的讨论。 这里是内置的bash手册部分。
“ set -e
”可能是最简单的方法。 只要把你的程序中的任何命令之前。
如果你只是在没有参数的bash中调用exit,它将返回最后一个命令的退出代码。 与OR相结合,如果前面的命令失败,bash只能调用exit。 但是我没有testing过这个。
command1 || 出口; command2 || 出口;
Bash还会将最后一个命令的退出代码存储在variables$?中。
http://cfaj.freeshell.org/shell/cus-faq-2.html#11
-
如何在
cmd1|cmd2
获取cmd1
的退出码首先,请注意,
cmd1
退出代码可能不为零,但仍然不代表错误。 这发生在例如cmd | head -1
您可能会观察到
cmd1
的141(或ksh93的269)退出状态,但这是因为当读取一行后,head -1
终止时,cmd
被SIGPIPE信号中断。要知道pipe道
cmd1 | cmd2 | cmd3
的元素的退出状态cmd1 | cmd2 | cmd3
一个。 用zsh:
退出代码在pipestatus特殊数组中提供。
cmd1
退出代码在$pipestatus[1]
,cmd3
退出代码在$pipestatus[3]
,这样$?
总是和$pipestatus[-1]
。湾 与bash:
退出代码在
PIPESTATUS
特殊数组中提供。cmd1
退出代码在${PIPESTATUS[0]}
,cmd3
退出代码在${PIPESTATUS[2]}
,这样$?
总是和${PIPESTATUS: -1}
。…
欲了解更多详情,请参阅以下链接 。
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
为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