如何在 Bash 函数中捕获和处理非零退出状态?

如何在 Bash 函数中捕获和处理非零退出状态?

假设我有以下(毫无意义的)Bash 函数:

myfunc() {
    ls
    failfailfail
    uptime
}

我运行它如下:

myfunc || echo "Something is wrong."

我想要发生的是ls运行(因为它应该),failfailfail不起作用(因为它不存在),并且uptime不运行。该函数的返回值将不为零,并且将显示错误消息。返回值不必是失败命令的确切退出状态,它只是不应该为零。

实际发生的情况是我得到 的输出ls,然后是“-bash:failfailfail: command not find”,然后是 的输出uptime。错误消息不会显示,因为失败的退出状态正在被吃掉。

set -e无论是在函数内还是在调用函数的范围内都没有任何有用的效果。我能让它按照我想要的方式工作的唯一方法是:

myfunc() {
    ls || return $?
    failfailfail || return $?
    uptime || return $?
}

但这看起来非常重复且丑陋。还有其他方法可以清理这个吗?

答案1

在 下set -e, 的不存在failfailfail会导致整个脚本退出(或子 shell,如果该函数在子 shell 中执行)。

如果不需要从函数修改 shell 状态,则可以在子 shell 中运行它。

myfunc() (
    set -e
    ls
    failfailfail
    uptime
)

bash 中的另一种方法是设置ERR 陷阱执行return。如果要使其成为本地设置,则需要恢复旧的陷阱值,这有点麻烦。

myfunc() {
    local old_ERR_trap=$(trap -p ERR)
    if [[ -z $old_ERR_trap ]]; then old_ERR_trap="trap - ERR"; fi
    trap 'local ret=$?; eval "$old_ERR_trap"; return $ret' ERR
    ls
    failfailfail
    uptime
}

答案2

使它更简单的唯一方法是将其全部组合在一个命令中,但这使得脚本比上一个版本更难维护:

myfunc() {
    ls && failfailfail && uptime || return $?
}

答案3

鉴于它们都是简单的命令,您可以执行如下操作:

myfunc() {
  ls &&
  failfailfail &&
  uptime ||
  return $?
}

答案4

有时,最好将事情放在 Makefile 中,它可以处理此类事情。

#!/bin/bash
myfunc() { # watch out for tabs!
        make -f - <<!
default:
        ls -d
        failfailfail
        uptime
!
}

相关内容