如何在bash中返回陷阱后重新提示?

时间:2012-06-09 08:20:55

标签: bash shell signals

我有一个应该捕获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

用于完成后者的机制是什么?不幸的是,我不能简单地更改我的陷阱代码来执行重新提示,因为脚本会提示用户输入几个内容以及提示所说的内容依赖于上下文。并且必须有一种比编写依赖于上下文的陷阱函数更好的方法。

我非常感谢任何指针。谢谢!

2 个答案:

答案 0 :(得分: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,这是堆栈中的上一个函数。我们只是根据需要再次递归地再次调用它。

答案 1 :(得分:0)

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

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

现在光标仍然在空行处等待用户输入,但用户不会感到困惑,并点击&#34;输入&#34;按键提示。然后,脚本的输入验证检测到已输入空行,将其视为无效输入,并再次提示用户输入内容。

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