基于进程退出代码的退出Shell脚本
我有一个执行许多命令的Shell脚本。如果任何命令以非零退出代码退出,如何使shell脚本退出?
解决方案
在bash中,这很容易,只需将它们与&&绑在一起:
command1 && command2 && command3
我们还可以使用嵌套的if构造:
if command1 then if command2 then do_something else exit fi else exit fi
在每个命令之后,可以在$?
变量中找到退出代码,因此我们将获得类似以下内容的代码:
ls -al file.ext rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
我们需要注意管道命令,因为$?
只为我们提供管道中最后一个元素的返回代码,因此,在代码中:
ls -al file.ext | sed 's/^/xx: /"
如果文件不存在,则不会返回错误代码(因为管道的sed部分实际起作用,因此返回0)。
bash外壳实际上提供了一个可以在这种情况下提供帮助的数组,即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
"可能是最简单的方法。只需将其放在程序中的任何命令之前即可。
如果要使用$ ?,则需要在每个命令后进行检查,因为$?每个命令退出后更新。这意味着,如果我们执行管道,则只会获取管道中最后一个进程的退出代码。
另一种方法是执行此操作:
set -e set -o pipefail
如果将其放在shell脚本的顶部,bash似乎会为我们解决这个问题。如前所述," set -e"将导致bash退出,并在任何简单命令上出现错误。 " set -o pipefail"也将导致bash退出,并且管道中的任何命令也会出错。
有关此问题的更多讨论,请参见此处或者此处。这是内置的bash手册部分。
如果我们仅在bash中调用exit而没有任何参数,它将返回最后一条命令的退出代码。如果与OR结合使用,则bash仅在前一个命令失败时才调用exit。但是我还没有测试过。
command1 || exit; command2 || exit;
Bash还将最后一个命令的退出代码存储在变量$?中。
对于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; }
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信号中断。了解管道cmd1 |的元素的退出状态| cmd2 | cmd3
使用zsh:在pipestatus特殊数组中提供了退出代码。 cmd1退出代码位于$ pipestatus [1]中,cmd3退出代码位于$ pipestatus [3]中,因此$?与$ pipestatus [-1]始终相同。 b。带有bash:退出代码在" PIPESTATUS"特殊数组中提供。 cmd1退出代码位于$$ PIPESTATUS [0]}中,cmd3退出代码位于$ {PIPESTATUS [2]}中,因此$?始终与$ {PIPESTATUS: 1}`。 ...有关更多详细信息,请参见以下链接。