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
是否实际连接到陷阱调用,但我得到了相同的结果。我也尝试过将 set
和 shopt
条目也放入子 shell 中——同样没有改变行为。
环境:
- bash-4.2.46-21.el7_3.x86_64:这是一个要求,但是POSIX合规性不是必需的。我也对以后的 Bash 版本(4.2+)感兴趣。
- CentOS 7+: 虽然主要对 CentOS 感兴趣,但我最终会需要它来部署在 Ubuntu 16.04+ 和 CentOS 上的 Bash 脚本还有6个。
是否可以获取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 的洞察力。我等几天看看他有没有在这里发布解决方案来接受他的回答;否则,我会将此标记为已接受的答案并感谢他。
对于 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
是否实际连接到陷阱调用,但我得到了相同的结果。我也尝试过将 set
和 shopt
条目也放入子 shell 中——同样没有改变行为。
环境:
- bash-4.2.46-21.el7_3.x86_64:这是一个要求,但是POSIX合规性不是必需的。我也对以后的 Bash 版本(4.2+)感兴趣。
- CentOS 7+: 虽然主要对 CentOS 感兴趣,但我最终会需要它来部署在 Ubuntu 16.04+ 和 CentOS 上的 Bash 脚本还有6个。
是否可以获取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 的洞察力。我等几天看看他有没有在这里发布解决方案来接受他的回答;否则,我会将此标记为已接受的答案并感谢他。