为什么陷阱ERR在bash的子函数中失败?

时间:2018-02-12 05:26:08

标签: bash

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

所以,我希望我可以使用trap ERR来显示错误行。 但是,它失败了,在下面的测试脚本中尝试停在subs1,但只有sub2会被陷阱停止。当退出代码不是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

1 个答案:

答案 0 :(得分:2)

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

set -E

根据help set

  

-E如果设置,则shell函数将ERR陷阱继承

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