我有一个执行许多命令的shell脚本。 如果任何命令以非零退出代码退出,如何使shell脚本退出?
在每个命令之后,退出代码可以在$?变量中找到,所以你会得到类似的东西:
1 2
| ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi |
您需要注意管道命令,因为$?只提供管道中最后一个元素的返回码,因此,在代码中:
1
| ls -al file.ext | sed 's/^/xx: /" |
如果文件不存在,则不会返回错误代码(因为管道的sed部分实际工作,返回0)。
bash shell实际上提供了一个可以在这种情况下提供帮助的数组,即PIPESTATUS。此数组为每个管道组件都有一个元素,您可以像${PIPESTATUS[0]}一样单独访问:
1 2
| pax> false | true ; echo ${PIPESTATUS[0]}
1 |
请注意,这将使您获得false命令的结果,而不是整个管道。您还可以根据需要获取整个列表进行处理:
1 2
| pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1 |
如果您想从管道中获取最大的错误代码,可以使用以下内容:
1 2 3
| 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中。
如果你想使用$ ?,你需要在每个命令之后检查它,因为$?每个命令退出后更新。这意味着如果执行管道,您将只获得管道中最后一个进程的退出代码。
另一种方法是这样做:
如果你把它放在shell脚本的顶部,看起来bash会为你处理这个问题。正如之前的一张海报所指出的那样,"set -e"会导致bash在任何简单命令上都出错。"set -o pipefail"将导致bash退出,同时管道中的任何命令都会出错。
请参阅此处或此处以获取有关此问题的更多讨论。这是set builtin上的bash手册部分。
"set -e"可能是最简单的方法。只需将它放在程序中的任何命令之前。
如果你只是在没有参数的bash中调用exit,它将返回最后一个命令的退出代码。结合OR,如果前一个命令失败,bash应该只调用exit。但我没有测试过这个。
1 2
| command1 || exit;
command2 || exit; |
Bash还会将最后一个命令的退出代码存储在变量$?中。
1
| [ $? -eq 0 ] || exit $?; # exit for none-zero return code |
http://cfaj.freeshell.org/shell/cus-faq-2.html#11
如何在cmd1|cmd2中获取cmd1的退出代码
首先,请注意cmd1退出代码可能不为零,但仍然没有
意味着错误。例如,这发生在
您可能会观察到141(或269与ksh93)退出状态cmd1,
但这是因为cmd被SIGPIPE信号中断了
读取一行后head -1终止。
要知道管道元素的退出状态
cmd1 | cmd2 | cmd3
一个。用zsh:
退出代码在pipestatus特殊数组中提供。
cmd1退出代码位于$pipestatus[1],cmd3退出代码中
$pipestatus[3],因此$?始终与...相同
$pipestatus[-1]。
湾用bash:
退出代码在PIPESTATUS特殊数组中提供。
cmd1退出代码位于${PIPESTATUS[0]},cmd3退出代码中
${PIPESTATUS[2]},因此$?始终与...相同
${PIPESTATUS: -1}。
...
有关详细信息,请参阅以下链接。
对于bash:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| # 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中这很容易,只需用&&将它们绑在一起:
1
| command1 && command2 && command3 |
您还可以使用嵌套的if结构:
1 2 3 4 5 6 7 8 9 10 11
| if command1
then
if command2
then
do_something
else
exit
fi
else
exit
fi |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #
#------------------------------------------------------------------------------
# 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 |