以下代码触发调试陷阱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)
我敢肯定,我只是误解了手册,在这里我遗漏了一些非常简单/显而易见的内容。
答案 0 :(得分:2)
我假设您了解,DEBUG
陷阱允许在每个其他Shell命令之前运行其定义(trap 'action' signal
)中定义的命令,并且set -T
允许对所有子Shell和功能的陷阱也。因此,一旦您设置了trap
,就将执行三个处决。
foo
,在此之前一旦触发trap
,就会导致打印字符串的第一个实例。echo oops
定义中有一个trap
命令,其中echo
只是另一个命令,因此在运行{{1} }被解雇。trap
中的实际echo
命令产生了第三个实例trap
紧随hello
执行完毕之后。查看从调试模式运行时的顺序
trap
添加更多解释来解释该序列,假设在运行任何shell函数/命令之前 触发了$ bash -x script.sh
+ set -T
+ trap 'echo oops' DEBUG
++ echo oops # <--- triggered by call to 'foo'
oops
+ foo
++ echo oops # <--- triggered by call to 'echo oops' inside trap definition
oops
++ echo oops # <--- result of the actual command to be run
oops
+ echo hello # <--- result of the function call 'foo'
hello
陷阱。让我们细分为以下内容。理解这是两个指令/命令以及这些命令的两个结果动作
DEBUG
是第一条指令,因此将触发陷阱并立即运行操作foo
。请记住,echo oops
是触发器,foo
是 action ,我们第一次看到它。echo oops
,它会触发另一个动作,因此由于echo oops
,trap
被触发,然后实际的指令被触发了。完成,而恰好也echo oops
。答案 1 :(得分:2)
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. */
Here is the code执行调试陷阱:
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
命令,因此我将不包含它。