2010-01-18 5 views
94

ich ein langen Laufe Vermächtnis rubin-Programm übergeben wurde, die zahlreichen Vorkommen vonCapturing Ctrl-c in Ruby

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

überall hat.

Ohne Tracking jede einzelne mögliche Ausnahme nach unten diese jeweils Handhabung werden könnte (zumindest nicht sofort), würde ich immer noch in der Lage sein mag manchmal mit CtrlC herunterzufahren.

Und ich möchte dies in einer Weise tun, die nur auf den Code fügt hinzu (so dass ich nicht das bestehende Verhalten beeinflussen oder eine sonst abgefangene Ausnahme in der Mitte eines Laufs verpassen.)

[CtrlC ist SIGINT oder SystemExit, die SignalException.new("INT") in Rubys Ausnahmebehandlungssystem entspricht. class SignalException < Exception, weshalb dieses Problem aufkommt]

Der Code wäre ich geschrieben haben möchte.

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

EDIT: Dieser Code funktioniert, solange man die Klasse der Ausnahme erhalten Sie möchten korrekt abfangen. Das ist entweder SystemExit, Interrupt oder IRB :: Abort wie folgt.

Antwort

113

Das Problem ist, dass, wenn ein Ruby-Programm beendet wird, dies durch Erhöhung SystemExit. Wenn ein Steuerelement-C hereinkommt, erhöht es Interrupt. Da beide SystemExit und Interrupt von Exception ableiten, stoppt Ihre Ausnahmebehandlung den Exit oder Interrupt in seinen Spuren. Hier ist das Update:

Wo auch immer Sie können, ändern

rescue Exception => e 
    # ... 
end 

zu

rescue StandardError => e 
    # ... 
end 

für diejenigen, die Sie nicht auf Standarderror ändern, Reraise die Ausnahme:

rescue Exception => e 
    # ... 
    raise 
end 

oder zumindest SystemExit und Interrupt erneut aktivieren

Alle benutzerdefinierten Ausnahmen Sie gemacht haben von Standarderror, nicht Ausnahme ableiten sollte.

+0

Wayne, würden Sie so freundlich sein, ein IRB :: Abort-Beispiel zu Ihrer Liste hinzuzufügen? –

+1

@Tim, gehe zu irb.rb (auf meinem System ist es in /usr/lib/ruby/1.8/irb.rb) und finde die Hauptschleife (suche nach @ context.evaluate). Schauen Sie sich die Rettungsklauseln an und ich denke, Sie werden verstehen, warum sich IRB so verhält wie es tut. –

+0

danke. Ein Blick auf die Definition für #signal_handle in irb.rb hat mir ebenfalls geholfen. Sie haben einen ordentlichen Trick in der Hauptschleife ist die Ausnahme Variable Bindung. (Verwenden Sie die Rescue-Klauseln als eine Möglichkeit, eine bestimmte Ausnahme auszuwählen, dann diese Ausnahme außerhalb der Rettungskörper.) –

63

Wenn Sie Ihr ganzes Programm wickeln können, können Sie so etwas wie die folgenden tun:

trap("SIGINT") { throw :ctrl_c } 

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

Diese im Grunde hat CtrlC Verwendung catch/Handling statt Ausnahme auslösen, so dass, wenn der vorhandene Code bereits hat einen Haken: ctrl_c drin, es sollte in Ordnung sein.

Alternativ können Sie eine tun. exit! wird sofort beendet, es wird keine Ausnahme ausgelöst, sodass der Code sie nicht versehentlich abfangen kann.

+2

Beachten Sie, dass Ctrl-C in IRB IRB :: Abort, nicht SIGINT sendet. Ansonsten @ Logans Antwort ist eine Lösung. –

+1

@TimSnowhite für Ruby-Interpreter 'SIGINT' funktioniert gut für mich. – defhlt

+1

throw und catch müssen sich im selben Thread befinden, daher funktioniert dies nicht, wenn Sie die Interrupt-Ausnahme in einem anderen Thread abfangen möchten. –

25

Wenn Sie sich nicht wickeln Sie Ihre gesamte Anwendung in einem begin ... rescue Block (zum Beispiel Thor) kann man nur trap SIGINT:

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

130 ist ein Standard-Exit-Code.

+0

FYI, 130 ist der korrekte Exit-Code für Ctrl-C-unterbrochene Skripts: https://www.google.com/search?q=130+exit+code&en= ('130 | Skript beendet mit Strg-C | Ctl-C | Control-C ist fatales Fehlersignal 2, (130 = 128 + 2, so) ') – Dorian

3

Ich benutze ensure mit großer Wirkung! Dies ist für Dinge, die du passieren willst, wenn dein Zeug endet, egal, warum es endet.