5

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

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

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

环境:

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

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

4

2 回答 2

1
#!/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

Maybe I am missing something, but perhaps this will work for you...

于 2016-12-27T14:59:32.057 回答
1

我向 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 中的一个错误,解决方法是使用命令替换而不仅仅是一个 subshel​​l ()

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

于 2016-12-30T12:27:12.077 回答