3

我有一个应该捕获 SIGTERM 和 SIGTSTP 的脚本。这就是我在主块中的内容:

trap 'killHandling' TERM

在函数中:

killHandling () {
    echo received kill signal, ignoring
    return
}

... 和 SIGINT 类似。问题是用户界面之一。脚本会提示用户输入一些内容,如果在脚本等待输入时出现 SIGTERM 或 SIGINT,那就令人困惑了。这是这种情况下的输出:

Enter something:     # SIGTERM received
received kill signal, ignoring

      # shell waits at blank line for user input, user gets confused
      # user hits "return", which then gets read as blank input from the user
      # bad things happen because of the blank input

我肯定见过可以更优雅地处理此问题的脚本,如下所示:

Enter something:     # SIGTERM received
received kill signal, ignoring
Enter something:     # re-prompts user for user input, user is not confused

实现后者的机制是什么?不幸的是,我不能简单地更改我的陷阱代码来重新提示,因为脚本会提示用户几件事,并且提示所说的内容取决于上下文。并且必须有比编写依赖于上下文的陷阱函数更好的方法。

我将非常感谢任何指示。谢谢!

4

2 回答 2

2

这些不是非常健壮的方法——例如,它在第一个陷阱之后将 CTRL-C 作为字符处理的方式存在一些问题——但它们都处理您定义的用例。

使用 BASH_COMMAND 重新运行最后一个命令(例如读取)。

prompt () {
    read -p 'Prompting: '
}
reprompt () {
    echo >&2
    eval "$BASH_COMMAND"
}
trap "reprompt" INT
prompt

在这种情况下,*BASH_COMMAND* 的计算结果为read -p 'Prompting: '。然后需要使用 eval 重新处理该命令。如果你不评估它,你可能会遇到奇怪的引用问题。YMMV。

使用 FUNCNAME 重新运行调用堆栈中的前一个函数。

prompt () {
    read -p 'Prompting: '
}
reprompt () {
    echo >&2
    "${FUNCNAME[1]}"
}
trap "reprompt" INT
prompt

在此示例中,FUNCNAME[1]扩展为prompt,这是堆栈中的前一个函数。我们只是递归地再次调用它,根据需要多次调用。

于 2012-06-09T22:36:27.660 回答
0

CodeGnome 给出的答案是有效的,但正如他所指出的,它并不可靠;第二个 control-c 会导致不良行为。我最终通过更好地利用代码中现有的输入验证解决了这个问题。所以我的中断处理代码现在看起来像这样:

killHandling () {
   echo received kill signal, ignoring
   echo "<<Enter>> to continue"
   return
}

现在光标仍然在空白行等待用户输入,但用户没有混淆,按提示按“Enter”键。然后脚本的输入验证检测到输入了一个空行,将其视为无效输入,并重新提示用户输入内容。

我仍然感谢 CodeGnome 的建议,我从中学到了一些东西。对于延迟发布此答案,我深表歉意。

于 2012-08-21T01:09:59.873 回答