bash 根据进程退出码退出Shell脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/90418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 17:40:05  来源:igfitidea点击:

Exit Shell Script Based on Process Exit Code

bashshell

提问by Mark Roddy

I have a shell script that executes a number of commands. How do I make the shell script exit if any of the commands exit with a non-zero exit code?

我有一个执行许多命令的 shell 脚本。如果任何命令以非零退出代码退出,如何使 shell 脚本退出?

回答by paxdiablo

After each command, the exit code can be found in the $?variable so you would have something like:

在每个命令之后,可以在$?变量中找到退出代码,因此您将获得如下内容:

ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi

You need to be careful of piped commands since the $?only gives you the return code of the last element in the pipe so, in the code:

您需要小心管道命令,因为$?它只为您提供管道中最后一个元素的返回代码,因此在代码中:

ls -al file.ext | sed 's/^/xx: /"

will not return an error code if the file doesn't exist (since the sedpart of the pipeline actually works, returning 0).

如果文件不存在,则不会返回错误代码(因为sed管道的一部分实际工作,返回 0)。

The bashshell actually provides an array which can assist in that case, that being PIPESTATUS. This array has one element for each of the pipeline components, that you can access individually like ${PIPESTATUS[0]}:

bash壳实际上提供一种阵列,其可以协助在这种情况下,即是PIPESTATUS。对于每个管道组件,此数组都有一个元素,您可以单独访问这些元素,例如${PIPESTATUS[0]}

pax> false | true ; echo ${PIPESTATUS[0]}
1

Note that this is getting you the result of the falsecommand, not the entire pipeline. You can also get the entire list to process as you see fit:

请注意,这是为您提供false命令的结果,而不是整个管道。您还可以根据需要处理整个列表:

pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1

If you wanted to get the largest error code from a pipeline, you could use something like:

如果您想从管道中获取最大的错误代码,您可以使用以下内容:

true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc

This goes through each of the PIPESTATUSelements in turn, storing it in rcif it was greater than the previous rcvalue.

PIPESTATUS依次遍历每个元素,rc如果它大于先前的rc值,则将其存储。

回答by Jeff Hill

If you want to work with $?, you'll need to check it after each command, since $? is updated after each command exits. This means that if you execute a pipeline, you'll only get the exit code of the last process in the pipeline.

如果你想使用 $?,你需要在每个命令之后检查它,因为 $? 在每个命令退出后更新。这意味着如果你执行一个管道,你只会得到管道中最后一个进程的退出代码。

Another approach is to do this:

另一种方法是这样做:

set -e
set -o pipefail

If you put this at the top of the shell script, it looks like bash will take care of this for you. As a previous poster noted, "set -e" will cause bash to exit with an error on any simple command. "set -o pipefail" will cause bash to exit with an error on any command in a pipeline as well.

如果你把它放在 shell 脚本的顶部,看起来 bash 会为你处理这个问题。正如之前的海报所指出的,“set -e”将导致 bash 退出,并在执行任何简单命令时出错。"set -o pipefail" 也会导致 bash 退出,并在管道中的任何命令上出现错误。

See hereor herefor a little more discussion on this problem. Hereis the bash manual section on the set builtin.

有关此问题的更多讨论,请参见此处此处是 set 内置的 bash 手册部分。

回答by Allen

"set -e" is probably the easiest way to do this. Just put that before any commands in your program.

" set -e" 可能是最简单的方法。只需将其放在程序中的任何命令之前即可。

回答by Arvodan

If you just call exit in the bash with no parameters, it will return the exit code of the last command. Combined with OR the bash should only invoke exit, if the previous command fails. But I haven't tested this.

如果你只是在bash中不带参数调用exit,它会返回最后一条命令的退出码。结合 OR bash 应该只调用 exit,如果前一个命令失败。但我没有测试过这个。

command1 || exit;
command2 || exit;

The Bash will also store the exit code of the last command in the variable $?.

Bash 还将最后一个命令的退出代码存储在变量 $? 中。

回答by chemila

[ $? -eq 0 ] || exit $?; # exit for none-zero return code

回答by chemila

http://cfaj.freeshell.org/shell/cus-faq-2.html#11

http://cfaj.freeshell.org/shell/cus-faq-2.html#11

  1. How do I get the exit code of cmd1in cmd1|cmd2

    First, note that cmd1exit code could be non-zero and still don't mean an error. This happens for instance in

    cmd | head -1
    

    you might observe a 141 (or 269 with ksh93) exit status of cmd1, but it's because cmdwas interrupted by a SIGPIPE signal when head -1terminated after having read one line.

    To know the exit status of the elements of a pipeline cmd1 | cmd2 | cmd3

    a. with zsh:

    The exit codes are provided in the pipestatus special array. cmd1exit code is in $pipestatus[1], cmd3exit code in $pipestatus[3], so that $?is always the same as $pipestatus[-1].

    b. with bash:

    The exit codes are provided in the PIPESTATUSspecial array. cmd1exit code is in ${PIPESTATUS[0]}, cmd3exit code in ${PIPESTATUS[2]}, so that $?is always the same as ${PIPESTATUS: -1}.

    ...

    For more details see the following link.

  1. 我如何获得cmd1in的退出代码cmd1|cmd2

    首先,请注意cmd1退出代码可能不为零,但仍然不意味着错误。这发生在例如

    cmd | head -1
    

    您可能会观察到 141(或带有 ksh93 的 269)退出状态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}.

    ...

    有关详细信息,请参阅以下链接

回答by chemila

for 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;
}

回答by Martin W

In bash this is easy, just tie them together with &&:

在 bash 中,这很容易,只需将它们与 && 绑定在一起:

command1 && command2 && command3

You can also use the nested if construct:

您还可以使用嵌套的 if 构造:

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi

回答by Yordan Georgiev

#
#------------------------------------------------------------------------------
# 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