我可以在红宝石中捕获control-q和control-s吗?

时间:2012-09-11 18:39:18

标签: ruby signals

对于某些信号,比如SIGINT,我可以很容易地设置一个陷阱来处理信号并按我认为合适的方式继续执行。我想将^ q和^ s的典型行为添加到我正在摆弄的ruby命令行应用程序中。有没有办法做到这一点 - 特别是,一个可移植的,所以我可以在Windows,iOS,Linux和Solaris中使用它?

编辑:

事实证明,信号永远不会传递给过程。事实上,在进程及其父进程(一个bash实例)上运行strace表明,进程和父进程都没有得到任何指示。他们只是被停职了。

我可能会尝试使用每秒触发一次的SIGALARM处理程序,检查自上次警报以来是否超过一秒钟,并在结束该进程已被暂停时进行适当的调用。在负载很重的系统上会出现误报。

2 个答案:

答案 0 :(得分:1)

在irb中输入Signal.list。它将列出您应该捕获的所有信号。

在红宝石中捕获一个信号:

Signal.trap("STOP") do
  # handle the signal
end

在终端中输入$ stty -a。它应该列出信号及其相关的键组合(如果有的话)。

我相信^ s通常是stop而^ q是start

虽然根据this answer,这些关键组合实际上并不向正在运行的进程发送信号,而是向终端驱动程序发送信号。在这种情况下,kill -STOP <process>可以将该信号发送给您的流程。

答案 1 :(得分:1)

TL; DR不,您不能捕获它们,因为它们不会产生信号,并且终端下的进程看不到它们,只能通过启发式检测到它们。但是,如果要在终端程序中使用这些键绑定,那么可以,可以通过禁用终端对它们的特殊处理来实现。

^q^s不会产生信号。是^z而非^s导致了终端信令SIGSTOP

^s的作用是告诉终端不要读取正在写入终端的进程的输出。这导致进程在写入终端时阻塞(它们仍然可以写入其他地方并从stdin读取,以及进行其他操作)[1]。 ^q告诉终端继续读取和显示过程输出。将终端作为标准输入的进程看不到这些。终端会看到按键绑定,对其进行操作,并且不会将其传递给从其终端设备读取的进程。

您可以使用stty -ixon禁用此特殊行为,然后使用stty ixon重新启用它。当我禁用它时,在键入时读取的过程表明^s是字节0x13,而^q是字节0x11。不过,这在终端之间可能有所不同。

[1]作为显示此问题的实验,您可以打开2个终端窗口。在第二个设备上执行tty以找到其终端设备。然后,在第一终端上,您可以运行tee $TTY > $OTHER_TTY作为第二终端的终端设备,运行$OTHER_TTY。完成此操作后,您可以点击^s来阻止对终端的写入,并通过键入一些行来进行检查。该行将显示在第二个终端中,而不是第一个显示,此后,您键入的任何内容都不会显示,直到您按下^q为止。这里发生的是,在您击中^s并键入一行之后,tee仍然可以读取它,并将其输出到它的stdout,我们将其重定向到第二个终端。然后,当它尝试将其写入作为参数传递的第一个文件时,它被阻塞,因为它是您被^s阻塞的终端。它一直呆在那里,等待write()返回,直到您按下^q为止。