对于某些信号,比如SIGINT,我可以很容易地设置一个陷阱来处理信号并继续执行我认为合适的信号。我想将^ q和^ s的典型行为添加到我正在摆弄的ruby命令行应用程序中。有没有办法做到这一点 - 特别是,一个可移植的,所以我可以在Windows,iOS,Linux和Solaris中使用它?
编辑:
事实证明,信号永远不会传递给过程。事实上,在进程及其父进程(一个bash实例)上运行strace表明,进程和父进程都没有得到任何指示。他们只是被停职了。
我可能会尝试使用每秒触发一次的SIGALARM处理程序,检查自上次警报以来是否超过一秒钟,并在结束该进程已被暂停时进行适当的调用。在负载很重的系统上会出现误报。
在irb输入Signal.list
。它将列出您应该能够捕获的所有信号。
陷阱红宝石中的信号:
Signal.trap("STOP") do
# handle the signal
end
在终端输入$ stty -a
。它应该列出信号及其相关的密钥组合(如果有的话)。
我相信^ s通常是stop
而^ q是start
。
虽然根据this answer的说法,这些关键组合实际上并没有向正在运行的进程发送信号,而是向终端驱动程序发送信号。在这种情况下,kill -STOP <process>
可以将该信号发送到您的流程。
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
它不会。