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

问题描述:

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

+2

我回答假设你使用bash,但如果它是一个非常不同的外壳可以为您在您的文章中指定? – 2008-09-18 06:11:26

每个命令后,退出代码可以发现在$?变量,所以你会有这样的事情:

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

你需要小心管道命令,因为$?只给你在管道中最后一个元素的返回代码,这样,在代码:

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

如果文件没有按”将不返回错误代码(因为管道的sed部分实际工作,返回0)。

bash shell实际上提供了一个数组,可以在这种情况下提供帮助,即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 

这种经历如果它大于之前的rc值,则依次将PIPESTATUS元素中的每个元素存储在rc中。

+37

只有一行可移植代码具有相同的功能:`ls -al file.ext ||退出$?`([[]]不可移植) – MarcH 2010-11-10 23:44:31

+18

MarcH,我想你会发现'[[]]`在'bash`中是非常便携的,这就是问题的标记:-)奇怪的是, `ls`在`command.com`中不起作用,所以它不是可移植的,似乎我知道,但它与您提出的同样的论点。 – paxdiablo 2010-11-11 00:04:04

+35

我知道这是古老的,但应该注意的是,您可以通过数组`PIPESTATUS`(即`$ {PIPESTATUS [0]}`获得管道中命令的退出代码,第一个命令`$ { PIPESTATUS [1]}`为第二个,或`$ {PIPESTATUS [*]}`列出所有退出阶段 – DevSolar 2012-07-19 15:13:40

在bash这是很简单,只需用& &绑在一起:

command1 && command2 && command3 

您还可以使用嵌套如果构造:

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

set -e”可能是最简单的方法。只需在程序中的任何命令前加上。

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

另一种方法是做到这一点:

set -e 
set -o pipefail 

如果你把这个在shell脚本的顶部,它看起来像bash将照顾这对你。正如前面的海报所指出的那样,“set -e”会导致bash在任何简单命令中出错并退出。 “set -o pipefail”会导致bash在管道中的任何命令上出错并退出。

请参阅herehere关于此问题的更多讨论。 Here是关于set内建的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

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

    首先,请注意cmd1退出代码可能不为零,但仍然不是 表示有错误。出现这种情况,例如在

    cmd | head -1 
    

    你可能会观察到的cmd1, 一个141(或269 ksh93的)退出状态,但是这是因为cmd是由SIGPIPE信号时,看了一个行后终止 head -1中断。

    要知道管道 cmd1 | cmd2 | cmd3

    A的元素的退出状态。使用zsh:

    退出代码在pipestatus特殊数组中提供。 cmd1退出代码是$pipestatus[1],在 $pipestatus[3]cmd3退出代码,使$?总是一样 $pipestatus[-1]

    b。与bash:

    退出代码在PIPESTATUS特殊数组中提供。 cmd1退出代码是${PIPESTATUS[0]},在 ${PIPESTATUS[2]}cmd3退出代码,使$?总是一样 ${PIPESTATUS: -1}

    ...

    欲了解更多详细信息,请参见下面的link

开始=>

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

# 
#------------------------------------------------------------------------------ 
# run a command on failure exit with message 
# doPrintHelp: doRunCmdOrExit "$cmd" 
# call by: 
# set -e ; doRunCmdOrExit "$cmd" ; set +e 
#------------------------------------------------------------------------------ 
doRunCmdOrExit(){ 
    cmd="[email protected]" ; 

    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