我正在编写一个脚本,在启动服务之前等待一堆目录。它基本上由一个在结束时中断的无限循环组成,或者如果找不到任何所需的目录则继续。简化后,算法本身就像
loop_while_false() {
trap continue ERR
while true; do
printf .
sleep 1
false
break
done
trap ERR
echo
}
(我知道我可以使用until
或while !
完成此特定行为,但这与问题相关。)
第一次运行时,我得到一长串点的预期输出,直到我点击^ c。但如果我再次运行它,我只得到一个点。如果我不点击^ c,但重新定义循环是有限的,那么,在 new shell中,陷阱可以多次运行。但是为什么^ c会破坏shell的生命周期?甚至更奇怪(我在StackExchange升级硬件时花费了额外的时间)如果以这种方式编写函数,它不会破坏:
loop_while_noread() {
trap continue ERR
while true; do
printf .
read -t1 -n1
break
done
trap ERR
echo
}
除非您先运行loop_while_false
,否则请使用^ c将其终止。这是一个示例会话:
$ trap -p
trap -- 'shell_session_update' EXIT
$ loop_while_noread
...q
$ loop_while_noread
...r
$ loop_while_noread
....^C
$ loop_while_noread
..q
$ trap -p
trap -- 'shell_session_update' EXIT
trap -- 'continue' ERR
$ loop_while_false
.....^C
$ trap -p
trap -- 'shell_session_update' EXIT
trap -- 'continue' ERR
$ loop_while_false
.
$ loop_while_noread
.
好像sleep
或false
和trap
之间存在奇怪的关系。这是预期的行为吗?
我在OS X El Capitan上使用bash 3.2.57(1)-release。
答案 0 :(得分:4)
这肯定是一个错误。您可以通过将sleep命令更改为:
来解决此问题sleep 1||:
我找不到任何错误报告,但是我用gdb
对4.3.30(1)进行了一点点抨击,并确定在sleep 1
返回后出错(因为它被中断了),trap ERR
命令执行失败,导致SIG_INPROGRESS
标志永远不会重置为ERR
。该标志禁止将来执行trap ERR
,即使它仍然启用。
我没有进入执行失败的部分&#34 ;;当gdb跳过parse_and_execute (trap_command, tag, flags);
时,函数永远不会返回,我最后回到bash提示符,所以我想在某个时刻会发生longjmp。 (在SIG_INPROGRESS
返回后parse_and_execute
标志将被重置,因此函数不返回的事实解释了为什么标志没有重置。)
所有这些操作都位于trap.c
内的_run_trap_internal
。