在ruby中捕获Ctrl-c

时间:2010-01-18 21:42:01

标签: ruby exception copy-paste

我通过了一个长期运行的遗留ruby程序,该程序有很多次出现

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

贯穿始终。

如果没有追踪每一个可能的异常,这些异常都可以处理(至少不是立即),我仍然希望能够通过 Ctrl C <关闭它。 / KBD>

我想以一种只添加代码的方式这样做(所以我不会影响现有的行为,或者在运行过程中错过一个原本被捕获的异常。)

[ Ctrl C 是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,如下所示。

5 个答案:

答案 0 :(得分:122)

问题是当Ruby程序结束时,它会通过提升 SystemExit 来实现。当control-C进入时,它会引发 Interrupt 。由于 SystemExit Interrupt 都来自 Exception ,因此您的异常处理是在其轨道中停止退出或中断。这是修复:

您可以随时更改

rescue Exception => e
  # ...
end

rescue StandardError => e
  # ...
end

对于那些无法更改为StandardError的人,重新引发异常:

rescue Exception => e
  # ...
  raise
end

或者,至少重新提升SystemExit和Interrupt

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

您所做的任何自定义异常都应来自 StandardError ,而不是 Exception

答案 1 :(得分:68)

如果你可以包装整个程序,你可以执行以下操作:

 trap("SIGINT") { throw :ctrl_c }

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

这基本上有 Ctrl C 使用catch / throw而不是异常处理,所以除非现有的代码已经有了catch:ctrl_c,否则应该没问题。

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

答案 2 :(得分:30)

如果您无法将整个应用程序包裹在begin ... rescue块中(例如,Thor),则只能陷阱SIGINT

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

130是标准退出代码。

答案 3 :(得分:4)

我正在使用ensure效果很好!这是为了你想要在你的东西结束时发生的事情而不管它为什么结束。

答案 4 :(得分:-1)

使用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

Source