bash - 为什么bash的子函数中trap ERR失败?

标签 bash

我喜欢使用“set -e”在第一次出现错误时停止。 但如果没有设置“set -x”,则很难判断错误发生在哪一行。

所以,我希望我可以使用trap ERR来显示错误行。 但是,它失败了,在下面的测试脚本中尝试在 subs1 处停止,但只有 sub2 会被 trap 停止。当退出代码不为 0 时显示错误行号的正确方法是什么?

我的测试脚本如下

#!/bin/bash

subs() {
  echo "before false1: $LINENO"
  false 1
  echo "after false1: $LINENO"
}
subs2() {
  echo "before false2: $LINENO"
  false 2
}
failed() {
  local r=$?
  local line=${last_lineno:-$1}
  echo "Err: return $r at $line: $BASH_COMMAND"
  echo "Trace: " "$@"
  exit $r
}
main() {
  trap 'failed $LINENO ${BASH_LINENO[@]}' ERR
  subs
  subs2
  echo "end:$LINENO"
}
main "$@"

输出为(在 bash 4.4.12 上)

before false1: 4
after false1: 6
before false2: 9
Err: return 1 at 22: false 2
Trace:  22 25 0

最佳答案

您需要将此指令放在脚本的开头,以使您的 ERR 陷阱由 shell 函数继承。默认情况下,ERR 陷阱不会被继承。

set -E

根据帮助集:

-E If set, the ERR trap is inherited by shell functions.

Code Demo

您的完整代码:

#!/bin/bash
set -E

subs() {
  echo "before false1: $LINENO"
  false 1
  echo "after false1: $LINENO"
}

subs2() {
  echo "before false2: $LINENO"
  false 2
}

failed() {
  local r=$?
  set -- "${@:1:$(($#-1))}"
  # local line=${last_lineno:-$1}
  echo "Err: return $r at $1: $BASH_COMMAND"
  echo "Trace: " "$@"
  exit $r
}

main() {
  trap 'failed $LINENO ${BASH_LINENO[@]}' ERR
  subs
  subs2
  echo "end:$LINENO"
}

main "$@"

输出:

$> bash trapScript.sh

before false1: 5
Err: return 1 at 6: false 1
Trace:  6 26 31

关于bash - 为什么bash的子函数中trap ERR失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48740008/

相关文章:

mysql - Bash 脚本循环通过 MySQL

ios - 我有两个 Xcode 项目,找出其中两个文件不同的最简单方法是什么?

linux - 从所有子目录中的所有 mp3 文件中删除前 3 个字符和最后 1 个字符

bash - 带换行符的 Grep 搜索字符串

bash - 在 macOS 上计算 Bash 中的日期/时间差异

java - 如何构建一个像二进制文件一样的 google-chrome 包装脚本?

linux - 如何遍历awk中的列?

bash - 在 UNIX bash 脚本中编写 if 语句需要一些帮助

Linux 狂欢 : Move multiple different files into same directory

windows - Git 发出警告 : unable to rmdir