bash - 为什么 DEBUG 陷阱的执行次数比预期的要多?
问题描述
以下代码触发了 3 次调试陷阱。然而,我预计只有 2 次处决 - 一次执行foo
,第二次执行echo hello
:
foo() {
echo hello
}
set -T
trap 'echo oops' DEBUG
foo
输出:
oops
oops
oops
hello
预期输出:
oops
oops
hello
Bash
测试版本:
GNU bash, version 4.3.30(1)-release (x86_64-unknown-linux-gnu)
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
GNU bash, version 5.0.0(1)-alpha (x86_64-pc-linux-gnu)
我很确定我只是误解了手册,并且我在这里遗漏了一些非常简单/明显的东西。
解决方案
tl;dr:Bash 在调用函数时会额外运行一次调试陷阱,以允许中断函数本身而不是其第一个命令。以下是用于调用 bash 函数的源代码的execute_function :
/* Run the debug trap here so we can trap at the start of a function's
execution rather than the execution of the body's first command. */
源潜水时间
这是执行调试陷阱的代码:
int run_debug_trap () {
/* (...) */
trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
到今天为止,我在该行上放了一个断点trap.c:1081
,并查看了回溯:
第一个例子
Breakpoint 1, run_debug_trap () at trap.c:1081
1081 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
(gdb) where
#0 run_debug_trap () at trap.c:1081
#1 0x000055555559fd3d in execute_simple_command (simple_command=0x5555558aacc8, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x555555899148) at execute_cmd.c:4056
#2 0x0000555555599fd7 in execute_command_internal (command=0x5555558aae08, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x555555899148) at execute_cmd.c:807
#3 0x00005555555995c1 in execute_command (command=0x5555558aae08) at execute_cmd.c:405
#4 0x0000555555583c9e in reader_loop () at eval.c:180
#5 0x0000555555581794 in main (argc=2, argv=0x7fffffffe4d8, env=0x7fffffffe4f0) at shell.c:792
(gdb) up
#1 0x000055555559fd3d in execute_simple_command (simple_command=0x5555558aacc8, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x555555899148) at execute_cmd.c:4056
4056 result = run_debug_trap ();
(gdb) print *simple_command->words->word
$3 = {word = 0x5555558a5268 "foo", flags = 0}
换句话说,这是一个简单的命令foo
。到现在为止还挺好。
第二审
Breakpoint 1, run_debug_trap () at trap.c:1081
1081 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
(gdb) where
#0 run_debug_trap () at trap.c:1081
#1 0x00005555555a170a in execute_function (var=0x5555558ab648, words=0x5555558aac28, flags=0, fds_to_close=0x555555899148, async=0, subshell=0) at execute_cmd.c:4787
#2 0x00005555555a1c68 in execute_builtin_or_function (words=0x5555558aac28, builtin=0x0, var=0x5555558ab648, redirects=0x0, fds_to_close=0x555555899148, flags=0) at execute_cmd.c:5030
#3 0x00005555555a0660 in execute_simple_command (simple_command=0x5555558aacc8, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x555555899148) at execute_cmd.c:4330
#4 0x0000555555599fd7 in execute_command_internal (command=0x5555558aae08, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x555555899148) at execute_cmd.c:807
#5 0x00005555555995c1 in execute_command (command=0x5555558aae08) at execute_cmd.c:405
#6 0x0000555555583c9e in reader_loop () at eval.c:180
#7 0x0000555555581794 in main (argc=2, argv=0x7fffffffe4d8, env=0x7fffffffe4f0) at shell.c:792
这更有趣。我们仍在执行foo
之前的简单命令,但它又触发了!为什么呢?让我们看一下调用站点execute_cmd.c:4787:
/* Run the debug trap here so we can trap at the start of a function's
execution rather than the execution of the body's first command. */
showing_function_line = 1;
save_current = currently_executing_command;
result = run_debug_trap ();
换句话说,Bash 似乎故意再运行一次调试陷阱,目的是为了中断一个函数而不是它的第一个命令。
三审
不出所料是函数的echo
命令,所以我不会包括它。
推荐阅读
- css - 使用 `rgb(0 0 0 / 15%)` 在 CSS 中出现错误
- python-3.x - 从 Python 脚本中控制 VLC 媒体播放
- laravel - 关系子查询
- android - 未找到 Android SDK 文件 C:\Users\ASUS\AppData\Local\Android\sdk\platforms\android-29\android.jar
- javascript - 将 firebase 侦听器附加到 React 应用程序时丢失状态
- flutter - 使用 RxDart 观察 Hive 数据库中的数据
- reactjs - 带有过滤数据的 Redux 分页
- c++ - 一种将 `\e` 与 C++ 中的 `\e[A` 等转义键区分开来的方法
- javascript - GraphQL:如何重用“单个对象”解析器来加载相同对象的数组
- node.js - Typescript 类型不适用于 VS Code 中的包