如何使用 Trap 命令触发错误

如何使用 Trap 命令触发错误

我使用的是 Ubuntu 12.04.2。我正在尝试使用“trap”命令来捕获 shell 脚本中的异常或错误,但我也尝试手动触发“错误”退出。

我尝试过退出1,但它不会触发“错误”信号。

#!/bin/bash

func()
{
    exit 1
}

trap "echo hi" INT TERM ERR
func

不确定如何手动触发“错误”退出信号?

答案1

ERR陷阱不是当 shell 本身以非零错误代码退出时运行代码,而是当该 shell 运行的任何命令不属于状况(如 inif cmd...cmd || ......)以非零退出状态退出(与导致set -e退出 shell 的条件相同)。

如果您想在退出 shell 时以非零退出状态运行代码,您应该添加一个陷阱EXIT$?在那里进行检查:

trap '[ "$?" -eq 0 ] || echo hi' EXIT

但请注意,在捕获信号时,信号陷阱和 EXIT 陷阱都会运行,因此您可能需要这样做:

unset killed_by
trap 'killed_by=INT;exit' INT
trap 'killed_by=TERM;exit' TERM
trap '
  ret=$?
  if [ -n "$killed_by" ]; then
    echo >&2 "Ouch! Killed by $killed_by"
    exit 1
  elif [ "$ret" -ne 0 ]; then
    echo >&2 "Died with error code $ret"
  fi' EXIT

或者使用退出状态,如$((signum + 128))信号:

for sig in INT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig")))" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"' EXIT

但请注意,当您的父进程是一个像bash实现了等待并配合退出终端中断的处理。因此,您可能需要确保使用相同的信号来自杀,以便向您的父母报告您确实被打扰,并且如果它收到 SIGINT/SIGQUIT,也应该考虑退出。

unset killed_by
for sig in INT QUIT TERM HUP; do
  trap "exit $((128 + $(kill -l "$sig"))); killed_by=$sig" "$sig"
done
trap '
  ret=$?
  [ "$ret" -eq 0 ] || echo >&2 "Bye: $ret"
  if [ -n "$killed_by" ]; then
    trap - "$killed_by" # reset handler
    # ulimit -c 0 # possibly disable core dumps
    kill -s "$killed_by" "$$"
  else
    exec "$ret"
  fi' EXIT

如果您希望ERR触发陷阱,只需运行具有非零退出状态的命令,例如 falsetest

答案2

使用 return 而不是 exit 设置函数退出时的状态(如果函数在没有返回的情况下失败,则状态为最后执行的语句的状态。)如果您在问题的示例中替换returnexit它将按以下方式工作我认为您的意图是:陷阱将在 ERR 伪信号上触发,并且将打印“hi”。如需其他注意事项,请尝试以下操作:

#!/bin/bash

func()
{
    echo 'in func'
    return 99
    echo 'still in func'
}

trap 'echo "done"' EXIT
trap 'status=$?; echo "error status is $status"; trap - EXIT; exit $status' ERR
func
echo 'returned from func'

您可以尝试各种修改,例如返回 0、注释掉 ERR 陷阱、不取消 ERR 处理程序中的 EXIT 陷阱、不从 ERR 处理程序退出,或者删除 return 并将其作为falsefunc 中的最后一条语句。

相关内容