陷阱ERR只能工作一次?

时间:2016-02-14 20:03:35

标签: bash

我正在编写一个脚本,在启动服务之前等待一堆目录。它基本上由一个在结束时中断的无限循环组成,或者如果找不到任何所需的目录则继续。简化后,算法本身就像

loop_while_false() {
    trap continue ERR
    while true; do
        printf .
        sleep 1
        false
        break
    done
    trap ERR
    echo
}

(我知道我可以使用untilwhile !完成此特定行为,但这与问题相关。)

第一次运行时,我得到一长串点的预期输出,直到我点击^ 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 
.

好像sleepfalsetrap之间存在奇怪的关系。这是预期的行为吗?

我在OS X El Capitan上使用bash 3.2.57(1)-release。

1 个答案:

答案 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