माणिक में Ctrl-c कैप्चर करना


107

मैं एक लंबे समय तक चलने वाली रूबी कार्यक्रम पारित किया गया था, जिसमें कई घटनाएँ हैं

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

इसके दौरान।

हर एक संभावित अपवाद को ट्रैक किए बिना ये प्रत्येक को संभाल सकते हैं (कम से कम तुरंत नहीं), मैं अब भी इसे कई बार बंद करना चाहूंगा CtrlC

और मैं ऐसा करना चाहता हूं जो केवल कोड में जोड़ता है (इसलिए मैं मौजूदा व्यवहार को प्रभावित नहीं करता हूं, या एक रन के बीच में अन्यथा पकड़े गए अपवाद को याद नहीं करता हूं।)

[ CtrlCSIGINT, या SystemExit है, जो SignalException.new("INT")रूबी के अपवाद हैंडलिंग सिस्टम के बराबर प्रतीत होता है। class SignalException < Exception, जिसके कारण यह समस्या सामने आती है।]

मेरे द्वारा लिखा गया कोड निम्न होगा:

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

EDIT: यह कोड तब तक काम करता है, जब तक कि आप उस अपवाद के वर्ग को प्राप्त नहीं कर लेते, जिसे आप सही तरीके से फंसाना चाहते हैं। यह या तो नीचे के रूप में SystemExit, Interrupt, या IRB :: Abort है।

जवाबों:


132

समस्या यह है कि जब एक रूबी कार्यक्रम समाप्त होता है, तो सिस्टमएक्सिट को बढ़ाकर ऐसा करता है । जब एक नियंत्रण-सी अंदर आता है, तो यह बाधित होता है । चूंकि SystemExit और Interrupt दोनों अपवाद से प्राप्त होते हैं , इसलिए आपका अपवाद हैंडलिंग इसकी पटरियों में निकास या अवरोध को रोक रहा है। यहाँ तय है:

आप जहां भी कर सकते हैं, बदल सकते हैं

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 से प्राप्त किया जाना चाहिए , अपवाद नहीं ।


1
वेन, क्या आप अपनी सूची में IRB :: Abort उदाहरण जोड़ने के लिए इतने दयालु होंगे?
टिम स्नोहाइट

1
@Tim, irb.rb (मेरे सिस्टम पर, यह /usr/lib/ruby/1.8/irb.rb में है) पर जाएं और मुख्य लूप खोजें (@ संदर्भ के लिए खोजें)। बचाव खंड को देखें और मुझे लगता है कि आप समझेंगे कि आईआरबी जिस तरह से व्यवहार कर रहा है वह क्यों है।
वेन कॉनराड

धन्यवाद। Irb.rb में #signal_handle की परिभाषा देखने से मेरी समझ में भी मदद मिली। उनके पास मुख्य लूप के साथ-साथ अपवाद चर बंधन के भीतर एक साफ चाल है। (एक विशिष्ट अपवाद को बाहर निकालने के तरीके के रूप में बचाव खंड का उपयोग करना, फिर बचाव निकायों के बाहर उस अपवाद का उपयोग करना।)
टिम स्नोइट

ये सही काम करता है:rescue SystemExit, Interrupt raise rescue Exception => e
जेम्स टैन

73

यदि आप अपना पूरा कार्यक्रम लपेट सकते हैं, तो आप निम्न कार्य कर सकते हैं:

 trap("SIGINT") { throw :ctrl_c }

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

यह मूल रूप CtrlCसे अपवाद से निपटने के बजाय कैच / थ्रो का उपयोग करता है, इसलिए जब तक कि मौजूदा कोड में पहले से ही एक कैच न हो: इसमें ctrl_c, यह ठीक होना चाहिए।

वैकल्पिक रूप से आप कर सकते हैं trap("SIGINT") { exit! }exit!तुरंत बाहर निकलता है, यह एक अपवाद नहीं बढ़ाता है ताकि कोड गलती से इसे पकड़ न सके।


2
ध्यान दें कि IRB में Ctrl-C IRB :: Abort भेजता है, SIGINT नहीं। अन्यथा @ लोगन का जवाब एक समाधान है।
टिम स्नोहाइट

1
रूबी दुभाषिया के लिए @TimSnowhite SIGINTमेरे लिए ठीक काम करता है।
डिफॉल्ट

1
थ्रो और कैच एक ही थ्रेड पर होना चाहिए, इसलिए यदि आप किसी अन्य थ्रेड पर इंटरप्ट अपवाद को पकड़ना चाहते हैं तो यह काम नहीं करेगा।
मैट कोनोली

39

यदि आप अपने पूरे एप्लिकेशन को किसी begin ... rescueब्लॉक (जैसे, थॉर) में नहीं लपेट सकते हैं तो आप बस फंस सकते हैं SIGINT:

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

130 एक मानक निकास कोड है।


1
FYI करें, 130 Ctrl-C बाधित स्क्रिप्ट के लिए सही निकास कोड है: google.com/search?q=130+exit+code&en= ( 130 | Script terminated by Control-C | Ctl-C | Control-C is fatal error signal 2, (130 = 128 + 2, see above))
Dorian

उत्तम! मेरे पास लगातार चलने वाले बैकग्राउंड थ्रेड के साथ एक विस्की सिनात्रा सर्वर है, और यह इस तरह दिखता है कि मुझे थ्रेड को मारने के साथ-साथ एक cntrl-c पर, अन्यथा बिना बदले व्यवहार की आवश्यकता है।
Narfanator

4

मैं ensureबहुत प्रभाव का उपयोग कर रहा हूँ ! यह उन चीजों के लिए है जो आप चाहते हैं कि जब आपका सामान समाप्त हो जाए तो कोई फर्क नहीं पड़ता।


0

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

स्रोत


अच्छा उदाहरण है, लेकिन मुझे लगता है कि यह ओपी के संदर्भ में वास्तव में जरूरत से ज्यादा जटिलता जोड़ता है।
रॉन क्लेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.