tcl8.6:stdlib 中的 'atexit()' 或 bash 中的 'trap "..." EXIT' 的内置等效项是什么?
tcl8.6: what is the built-in equivalent to 'atexit()' in stdlib or 'trap "..." EXIT' in bash?
我正在寻找一个内置或标准包,它提供与 stdlib 的 atexit()
和 bash' trap "..." EXIT
.
相似或等效的功能
它应该捕获由于任何结束执行的编程方式而导致的终止,包括以下所有方式:
- 脚本执行自然结束
- 明确调用
exit
- 未捕获
error
在大多数情况下,拦截此类终止所需要做的就是拦截exit
命令。
rename exit real_exit
proc exit args {
puts "EXITING"; flush stdout; # Flush because I'm paranoid...
tailcall real_exit {*}$args
}
如果您显式调用它,这显然会起作用,但如果您只是放下脚本的末尾,在交互式会话中发出文件结束信号,或者如果您的脚本稍后出现错误,它也会被调用并以错误消息终止。这是因为 Tcl C API 调用 Tcl_Exit()
通过调用 exit
工作,如果不退出进程,则直接退出。
顺便说一下,小心退出脚本;其中的错误比正常情况下更难调试。
在哪些情况下不起作用?主要是解释器本身变得无法执行命令(可能是因为它已从其自身下删除)或某些信号关闭解释器(例如,由于各种原因默认情况下未处理 SIGINT)。
一个或多或少完整的atexit
基于@Donal的回答:
proc atexit { procbody } {
if { [catch {set oldbody [info body exit]}] } {
rename exit builtin_exit
set oldbody { builtin_exit $returnCode }
}
proc exit { {returnCode 0} } [subst -nocommands {
apply [list [list {returnCode 0}] [list $procbody]] $returnCode
tailcall apply [list [list {returnCode 0}] [list $oldbody]] $returnCode
}]
}
atexit-test.tcl
的示例代码:
#!/usr/bin/tclsh8.6
source atexit.tcl
atexit {
puts "EXITING($returnCode)"; flush stdout; # Flush because I'm paranoid...
}
atexit {
puts "done($returnCode)..."; flush stdout; # Flush because I'm paranoid...
}
atexit {
puts "almost($returnCode)..."; flush stdout; # Flush because I'm paranoid...
}
{*}$argv
puts "fell through argv for implicit exit..."
...和终端会话:
$ ./atexit-test.tcl
fell through argv for implicit exit...
almost(0)...
done(0)...
EXITING(0)
$ ./atexit-test.tcl exit
almost(0)...
done(0)...
EXITING(0)
$ ./atexit-test.tcl exit 5
almost(5)...
done(5)...
EXITING(5)
$ ./atexit-test.tcl error "unhandled exception"
unhandled exception
while executing
"{*}$argv"
(file "./atexit-test.tcl" line 17)
almost(1)...
done(1)...
EXITING(1)
$
我正在寻找一个内置或标准包,它提供与 stdlib 的 atexit()
和 bash' trap "..." EXIT
.
它应该捕获由于任何结束执行的编程方式而导致的终止,包括以下所有方式:
- 脚本执行自然结束
- 明确调用
exit
- 未捕获
error
在大多数情况下,拦截此类终止所需要做的就是拦截exit
命令。
rename exit real_exit
proc exit args {
puts "EXITING"; flush stdout; # Flush because I'm paranoid...
tailcall real_exit {*}$args
}
如果您显式调用它,这显然会起作用,但如果您只是放下脚本的末尾,在交互式会话中发出文件结束信号,或者如果您的脚本稍后出现错误,它也会被调用并以错误消息终止。这是因为 Tcl C API 调用 Tcl_Exit()
通过调用 exit
工作,如果不退出进程,则直接退出。
顺便说一下,小心退出脚本;其中的错误比正常情况下更难调试。
在哪些情况下不起作用?主要是解释器本身变得无法执行命令(可能是因为它已从其自身下删除)或某些信号关闭解释器(例如,由于各种原因默认情况下未处理 SIGINT)。
一个或多或少完整的atexit
基于@Donal的回答:
proc atexit { procbody } {
if { [catch {set oldbody [info body exit]}] } {
rename exit builtin_exit
set oldbody { builtin_exit $returnCode }
}
proc exit { {returnCode 0} } [subst -nocommands {
apply [list [list {returnCode 0}] [list $procbody]] $returnCode
tailcall apply [list [list {returnCode 0}] [list $oldbody]] $returnCode
}]
}
atexit-test.tcl
的示例代码:
#!/usr/bin/tclsh8.6
source atexit.tcl
atexit {
puts "EXITING($returnCode)"; flush stdout; # Flush because I'm paranoid...
}
atexit {
puts "done($returnCode)..."; flush stdout; # Flush because I'm paranoid...
}
atexit {
puts "almost($returnCode)..."; flush stdout; # Flush because I'm paranoid...
}
{*}$argv
puts "fell through argv for implicit exit..."
...和终端会话:
$ ./atexit-test.tcl
fell through argv for implicit exit...
almost(0)...
done(0)...
EXITING(0)
$ ./atexit-test.tcl exit
almost(0)...
done(0)...
EXITING(0)
$ ./atexit-test.tcl exit 5
almost(5)...
done(5)...
EXITING(5)
$ ./atexit-test.tcl error "unhandled exception"
unhandled exception
while executing
"{*}$argv"
(file "./atexit-test.tcl" line 17)
almost(1)...
done(1)...
EXITING(1)
$