web-dev-qa-db-ja.com

rubyでCtrl-cをキャプチャする

私は長い間実行されているレガシーRubyプログラムに合格しました。

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

それ全体。

すべての可能な例外を追跡せずに、これらのそれぞれが処理している可能性があります(少なくともすぐにではありません)。 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のいずれかです

100
Tim Snowhite

問題は、Rubyプログラムが終了するとき、SystemExitを上げることによってそうすることです。control-Cが入ってくると、Interruptを上げます。 =。SystemExitInterruptの両方がExceptionから派生しているため、例外処理はそのトラックで出口または割り込みを停止しています。

どこでもできる

rescue Exception => e
  # ...
end

rescue StandardError => e
  # ...
end

standardErrorに変更できない場合は、例外を再度発生させます。

rescue Exception => e
  # ...
  raise
end

または、少なくともSystemExitと割り込みを再発生させます

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

作成したカスタム例外は、ExceptionではなくStandardErrorから派生する必要があります。

123
Wayne Conrad

プログラム全体をラップできる場合は、次のようなことができます。

_ 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!_はすぐに終了しますが、例外を発生させないため、コードが誤ってキャッチすることはありません。

69
Logan Capaldo

アプリケーション全体をbegin ... rescueブロック(たとえば、Thor)でラップできない場合は、SIGINTをトラップできます。

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

130は標準の終了コードです。

36
Erik Nomitch

私はensureを非常に効果的に使用しています!これは、何が終了したとしても、あなたのスタッフが終了したときに起こりたいことのためです。

4
nroose

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

ソース

0
noraj