基于进程退出代码的退出Shell脚本

时间:2020-03-06 14:20:09  来源:igfitidea点击:

我有一个执行许多命令的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}`。 ...有关更多详细信息,请参见以下链接。