当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《基于进程退出代码退出Shell脚本》经验,为你挑选了8个好方法。

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



1> paxdiablo..:

在每个命令之后,退出代码可以在$?变量中找到,所以你会有类似的东西:

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值,则将其存储.


我知道这是古老的,但应注意的是,你可以通过阵列`PIPESTATUS` get命令的退出代码在管道(即`$ {PIPESTATUS [0]}`第一个命令,`$ {PIPESTATUS [1]}`为第二个,或`$ {PIPESTATUS [*]}`为所有退出站的列表.
只有一行可移植代码中的相同功能:`ls -al file.ext || 退出$?`([[]]不可移植)
MarcH,我想你会发现`[[]]`在`bash`中非常便携,这就是标记的问题:-)奇怪的是,`ls`在`command.com`中不起作用所以它也不是便携式的,我知道,似乎是你提出的那种论点.
需要强调的是,优雅和惯用的shell脚本很少需要直接检查`$?`.你通常想要像`if ls -al file.ext; 然后:没有; 否则退出$?; 当然像@MarcH所说的那些等同于`ls -al file.ext || 退出$?`但是如果`then`或`else`子句稍微复杂一点,那就更容易维护了.
`[[$ rc!= 0]]`会给你一个'0:not found`或`1:not found`错误.这应该改为`[$ rc -ne 0]`.还可以删除`rc = $?`并使用`[$?-ne 0]`.

2> Jeff Hill..:

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

另一种方法是这样做:

set -e
set -o pipefail

如果你把它放在shell脚本的顶部,看起来bash会为你处理这个问题.正如之前的一张海报所指出的那样,"set -e"会导致bash在任何简单命令上都出错."set -o pipefail"将导致bash退出,同时管道中的任何命令都会出错.

请参阅此处或此处以获取有关此问题的更多讨论. 这是set builtin上的bash手册部分.


这应该是最重要的答案:这比使用"PIPESTATUS"和检查各地的退出代码要容易得多.
`#!/ bin/bash -e`是启动shell脚本的唯一方法.你可以随时使用`foo ||之类的东西 handle_error $?`如果你需要实际检查退出状态.

3> Allen..:

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


它有什么作用?有任何文档链接吗?
如果脚本中的任何命令以错误状态退出并且您没有处理此错误,则@SwaroopCH`set -e`您的脚本将中止.
set -e等同于set -o errexit,可以搜索100%。搜索opengroup + errexit以获得官方文档。

4> Arvodan..:

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

command1 || exit;
command2 || exit;

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



5> chemila..:
[ $? -eq 0 ] || exit $?; # exit for none-zero return code


这不应该是``退出$?``(没有parens)?

6> 小智..:

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

    我如何获得的退出代码cmd1cmd1|cmd2

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

    cmd | head -1
    

    您可能会观察到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}.

    ...

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



7> 小智..:

对于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;
}


可能不应该"退出0",因为这表明成功.
exit_code = $?; echo"脚本因错误而中止";退出$ exit_code

8> Martin W..:

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

command1 && command2 && command3

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

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

推荐阅读
凹凸曼00威威_694
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有