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

Bash Trap: How to Get Line Number of a Subprocess with Non-Zero Status

对于 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

输出:

=== Trap Info: Status=73 LINENO=9 -- 25 0 A=1

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

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

环境:

是否可以获取returns非零状态的子进程的行号?如果不可能,是否有任何相关文件?如果存在解决方案,它应该可以很好地扩展而不会在代码中进行不必要的修饰。

#!/bin/bash

trapinfo()
{
   echo "=== Trap Info: Status=$? LINENO=$@ A=$A"
}

main()
{
   trap 'trapinfo $LINENO $SAVE_IT -- ${BASH_LINENO[*]}' ERR

   set -e
   set -E
   set -o errtrace
   shopt -s extdebug

   local -g A=1

   # false        # If uncommented, LINENO would be 19
   SAVE_IT=$LINENO && (exit 73)     # LINENO is magic, but a custom variable isn’t

   A=2
}

main

也许我遗漏了什么,但也许这对你有用...

我向 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

上面有3的输出。

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

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

上面有5的输出。

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

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

这也有所需的输出 5

所以,这个问题的解决方案似乎是 Bash 中的一个错误,解决方法是使用 command substitution 而不是仅使用子 shell ().

再次感谢 Eduardo Bustamante 的洞察力。我等几天看看他有没有在这里发布解决方案来接受他的回答;否则,我会将此标记为已接受的答案并感谢他。