Bash Trap:如何获取非零状态子进程的行号

Ste*_*ige 5 linux bash shell centos7 bash-trap

对于 Bash 程序:

 1  #!/bin/bash
 2  
 3  trapinfo()
 4  {
 5     echo "=== Trap Info: Status=$? LINENO=$@ A=$A"
 6  }
 7  
 8  main()
 9  {
10     trap 'trapinfo $LINENO -- ${BASH_LINENO[*]}' ERR
11  
12     set -e
13     set -E
14     set -o errtrace
15     shopt -s extdebug
16  
17     local -g A=1
18  
19     # false        # If uncommented, LINENO would be 19
20     (exit 73)      # LINENO is 9. How can I get 20 instead?
21  
22     A=2
23  }
24  
25  main
Run Code Online (Sandbox Code Playgroud)

输出:

=== Trap Info: Status=73 LINENO=9 -- 25 0 A=1
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种方法来拥有它,以便以非零状态退出的子shell被捕获trap并显示失败的子shell的行号。在上面的示例中,我正在寻找第 20 行作为结果。我注意到如果错误不在子shell中,我会得到想要的行号(见false上文)。

我尝试将陷阱移动到子外壳之前,以检查行号9是否实际连接到陷阱调用,但我得到了相同的结果。我还尝试将setshopt条目放入子shell 中——同样没有改变行为。

环境:

  • bash-4.2.46-21.el7_3.x86_64:这是一个要求,但不要求符合 POSIX。我也对以后的 Bash 版本(4.2+)感兴趣。
  • CentOS 7+:虽然主要对 CentOS 感兴趣,但我最终将需要它用于部署在 Ubuntu 16.04+ 和 CentOS 6 上的 Bash 脚本。

是否可以获取返回非零状态的子进程的行号?如果不可能,是否有任何文件可以说明这一点?如果存在解决方案,它应该可以很好地扩展,而无需在代码中进行不必要的修饰。

Ste*_*ige 2

我向 Bash 电子邮件组help-bash寻求帮助。Eduardo Bustamante 提供了以下两个代码块来指出 Bash 中可能存在的错误,该错误是此处困难的根源。

首先,对问题进行更简单的演示:

     1  #!/bin/bash
     2  shopt -s extdebug
     3  main() {
     4  trap 'echo $LINENO' ERR
     5  (exit 17)
     6  }
     7  main
Run Code Online (Sandbox Code Playgroud)

上面的输出为3.

接下来,考虑更改$(...)`...`

     1  #!/bin/bash
     2  shopt -s extdebug
     3  main() {
     4  trap 'echo $LINENO' ERR
     5  `exit 17`
     6  }
     7  main
Run Code Online (Sandbox Code Playgroud)

上面的输出为5.

现在,我做了自己的测试:

     1  #!/bin/bash
     2  shopt -s extdebug
     3  main() {
     4  trap 'echo $LINENO' ERR
     5  $(exit 17)
     6  }
     7  main
Run Code Online (Sandbox Code Playgroud)

这也具有所需的输出5

因此,这个问题的解决方案似乎是这是 Bash 中的一个错误,解决方法是使用命令替换而不仅仅是 subshel​​l ()

我再次感谢爱德华多·布斯塔曼特的洞察力。我会等几天看看他是否在这里发布解决方案以接受他的答案;否则,我会将其标记为已接受的答案并向他表示感谢。

  • 感谢所有参与的人。请参阅 http://lists.gnu.org/archive/html/help-bash/2017-01/msg00003.html,了解 Chet Ramey 确认该问题将在下一版本的 Bash 中修复的信息。将此标记为解决方案,确认解决方法是使用命令替换。 (2认同)