Capturing Ctrl-c in ruby

我通过了一个长期运行的遗留 Ruby 程序,它有许多出现的

begin
#dosomething
rescue Exception => e
#halt the exception's progress
end

throughout it.

在不追踪每一个可能的异常的情况下,这些异常都可以被处理(至少不是立即处理) ,我仍然希望有时能够用 CtrlC关闭它。

我希望这样做的方式只是增加代码(这样我就不会影响现有的行为,或者在运行的过程中错过一个异常)

[ CtrlC是 SIGINT,或 SystemExit,它似乎等同于 Ruby 异常处理系统中的 SignalException.new("INT")class SignalException < Exception,这就是为什么会出现这个问题。]

我想写的代码是:

begin
#dosomething
rescue SignalException => e
raise e
rescue Exception => e
#halt the exception's progress
end

编辑: 这段代码可以工作,只要你得到了你想要捕获正确的异常类。这是 SystemExit、 Interrupt 或 IRB: : Abort,如下所示。

52952 次浏览

问题是当一个 Ruby 程序结束时,它通过引发 SystemExit来结束。当一个控制 -C 进入时,它提高 打断一下。因为 SystemExit打断一下都是从 例外派生的,所以异常处理是在其轨道中停止退出或中断。解决办法是:

无论你在哪里,改变

rescue Exception => e
# ...
end

rescue StandardError => e
# ...
end

for those you can't change to StandardError, re-raise the exception:

rescue Exception => e
# ...
raise
end

或者,至少重新启动 SystemExit 和 Interrupt

rescue SystemExit, Interrupt
raise
rescue Exception => e
#...
end

任何自定义异常都应该从 标准错误派生,而不是从 例外派生。

If you can wrap your whole program you can do something like the following:

 trap("SIGINT") { throw :ctrl_c }


catch :ctrl_c do
begin
sleep(10)
rescue Exception
puts "Not printed"
end
end

这基本上使 CtrlC使用 catch/throw 代替异常处理,因此除非现有代码中已经有 catch: ctrl _ c,否则应该没有问题。

或者你可以做一个 trap("SIGINT") { exit! }exit!立即退出,它不会引发异常,因此代码不会意外地捕获它。

如果不能将整个应用程序包装在 begin ... rescue块中(例如,Thor) ,那么只需捕获 SIGINT:

trap "SIGINT" do
puts "Exiting"
exit 130
end

130是标准的出口代码。

我使用 ensure的效果非常好!这是为了你想要发生的事情,当你的事情结束时,不管它为什么结束。

在 Ruby 中干净利落地处理 Ctrl-C ZeroMQ 方式:

#!/usr/bin/env ruby


# Shows how to handle Ctrl-C
require 'ffi-rzmq'


context = ZMQ::Context.new(1)
socket = context.socket(ZMQ::REP)
socket.bind("tcp://*:5558")


trap("INT") { puts "Shutting down."; socket.close; context.terminate; exit}


puts "Starting up"


while true do
message = socket.recv_string
puts "Message: #{message.inspect}"
socket.send_string("Message received")
end

来源

Perhaps the most simple solution?

Signal.trap('INT') { exit }

这是我使用的,它的工作。把它的地方 之前一个可能的用户交互。

这里有一个更详细的解决方案,可以打印一些内容到 STDERR 并退出:

Signal.trap('INT') { abort 'Interrupted by user' }

有关退出和中止之间的差异,请参见 在这里 < a href = “ https://stackoverflow. com/questions/23340609/what-is-the-different-between-exit-and-abort”>