如何在Bash脚本中捕获退出代码

Dag*_*ang 42 bash signals exit-code bash-trap

我的bash代码中有很多退出点.我需要在退出时做一些清理工作,所以我使用trap为这样的退出添加一个回调:

trap "mycleanup" EXIT
Run Code Online (Sandbox Code Playgroud)

问题是有不同的退出代码,我需要做相应的清理工作.我可以在mycleanup中获得退出代码吗?

Pau*_*ias 48

接受的答案基本上是正确的,我只想澄清一些事情.

以下示例运行良好:

#!/bin/bash

cleanup() {
    rv=$?
    rm -rf "$tmpdir"
    exit $rv
}

tmpdir="$(mktemp)"
trap "cleanup" INT TERM EXIT
# Do things...
Run Code Online (Sandbox Code Playgroud)

但是如果在没有函数的情况下进行内联清理,你必须更加小心.例如,这不起作用:

trap "rv=$?; rm -rf $tmpdir; exit $rv" INT TERM EXIT
Run Code Online (Sandbox Code Playgroud)

相反,你必须转义$rv$?变量:

trap "rv=\$?; rm -rf $tmpdir; exit \$rv" INT TERM EXIT
Run Code Online (Sandbox Code Playgroud)

您可能还想要转义$tmpdir,因为它将在陷阱行执行时得到评估,如果tmpdir值稍后更改,则不会给出预期的行为.

编辑:使用shellcheck检查bash脚本并注意这样的问题.

  • 或者你可以使用单引号:trap'rv = $?; rm -rf $ tmpdir; 退出$ rv'INT TERM EXIT (4认同)

bmk*_*bmk 47

我想你可以$?用来获取退出代码.

  • @Todd,@ bkk:不要忘记执行*any*命令会改变$?的值; 例如,myCmdIWantToTest; 回声$?; myRC = $?; ...现在myRC是echo $的'真相'?cmd被调用.如果myCmdIWantToTest退出'false',则该值将丢失.最好省钱?单独命名的var是唯一的.使用exitCode = $?通常,您可以轻松地结束继承其他cmd的exitCode(或更可能来自子shell(脚本)).另外,不要忘记它是OK测试退出代码作为if的一部分; 然后 ; ... fi.就像myCmdIWantToTest; 然后回声工作; 否则回声失败; 科幻 (5认同)
  • @Todd:变量`$ BASH_COMMAND`和`$ BASH_LINENO`有时也派上用场了. (2认同)

ant*_*ony 6

我发现最好将EXIT陷阱与其他信号分开

陷阱测试脚本示例...

umask 77
tmpfile=`tmpfile.$$`
trap 'rm -f "$tmpfile"' EXIT
trap 'exit 2' HUP INT QUIT TERM

touch $tmpfile
read -r input 

exit 10
Run Code Online (Sandbox Code Playgroud)

临时文件被清理。保留文件出口值10!中断导致退出值为2

基本上,只要您不在EXIT陷阱中使用“退出”,它就会以保留原始退出值的方式退出。

旁白:注意退出陷阱中的引用。这使我可以更改在脚本生存期内需要清除的文件。在尝试删除$ tmpfile之前,我通常还会对其进行测试,因此,我什至不需要在脚本开始时就对其进行设置,而只需在创建它之前。


ffl*_*res 6

下面的代码运行良好。您可以存储退出代码并定义陷阱函数中每个退出代码所需的命令。

#!/bin/bash
trap cleanup EXIT
cleanup() {
   exit_code=$?
   if [[ ${exit_code} -eq 1 ]]; then
       # command 1
   elif [[ ${exit_code} -eq 2 ]]; then
       # command 2
   elif [[ ${exit_code} -eq 3 ]]; then
       # command 3
   fi
}
Run Code Online (Sandbox Code Playgroud)