Capturing Ctrl-c in ruby
The problem is that when a Ruby program ends, it does so by raising SystemExit. When a control-C comes in, it raises Interrupt. Since both SystemExit and Interrupt derive from Exception, your exception handling is stopping the exit or interrupt in its tracks. Here's the fix:
Wherever you can, change
rescue Exception => e
# ...
end
to
rescue StandardError => e
# ...
end
for those you can't change to StandardError, re-raise the exception:
rescue Exception => e
# ...
raise
end
or, at the very least, re-raise SystemExit and Interrupt
rescue SystemExit, Interrupt
raise
rescue Exception => e
#...
end
Any custom exceptions you have made should derive from StandardError, not Exception.
Ruby: Nice text on ^C (ctrl+C) command-line interrupt
Doing ctrl + c simply sends SIGINT
signal to the given ruby process. You can intercept it by rescuing Interrupt
:
begin
loop do
puts "foo bar baz"
end
rescue Interrupt
puts "\nExiting..."
end
How to disable control-c in ruby
you can trap SIGINT like this
trap "SIGINT" do
# this is called when you press control-c
# be very careful, you can't kill this program with control-c
end
You can also see Capturing Ctrl-c in ruby for some other ways to interact with control-c
How to capture Ctrl+C in a Python script which executes a Ruby script?
In your Ruby script:
trap('SIGINT') { exit 1 }
In your Python script, os.system()
should return the value passed to exit
. You can use that redirect the flow of control however needed, e.g. call sys.exit()
.
Ctrl-C doesn't quit program when using sytem() in Ruby
Kernel#system
executes a given command in a sub-shell. Which means that Ctrl-C is going to that subshell and not your ruby script, so there's no use trapping it there. However, the command returns a value which indicates, whether it was completed successfully or not. When the command is stopped via Ctrl-C, it won't count as a successful completion. So, check the return value.
5.times do |i|
puts "Iteration #{i}"
success = system("sleep 3")
break unless success
end
Rescue/capture ctrl-break
ctrl-break sends SIGBREAK
, so this would be the expected way to handle it:
trap("BREAK") { puts "ctrl-break" }
Unfortunately, Ruby doesn't know (SIG)BREAK
, so you have to use the signal number instead, which should be 21
:
trap(21) { puts "ctrl-break" }
ctrl-c can be handled accordingly, i.e.:
trap("INT") { puts "ctrl-c" }
Ctrl-c no longer kills my program
If your program runs on some flavor of Unix, you could catch the INT signal(sent by Ctrl-C) and call exit
explicitly.
Put this before or after your begin
block:
Signal.trap('INT') { exit 0 }
Additionally you could do some cleanup before exiting your program:
Signal.trap('INT') do
# some cleanup here
puts "Interrupted by user"
exit 0
end
More on signals in Ruby
Unix signals list
How do I configure ruby to enter the debugger on Ctrl-C (SIGINT)?
If you want to trap SIGINT while running in the console, the short answer is: you cannot unless you monkey-patch IRB. Every Ruby app (whether padrino, or rails or whatnot) that uses the console will end up calling usr/lib/ruby/1.9.1/irb.rb
, and in IRB.start
, it does:
trap("SIGINT") do
irb.signal_handle
end
... just before entering the main loop. This will override any trap("SIGINT") you might have put in your startup code.
But if you want to trap SIGINT in a script file (for example, if you want to profile your code as described by Mike Dunlavey here), you can create a script file such as:
# File: profile_complex_operation.rb
trap("SIGINT") { debugger }
MyApp.complex_operation
and then invoke it as in:
$ ruby profile_complex_operation.rb
Now, when you hit ^C (or send SIGINT from another process), it will enter the debugger.
Related Topics
Ruby on Rails Source Code Security/Obfuscation
Scanning for Unicode Numbers in a String with \D
-': Nil Can't Be Coerced into Fixnum (Typeerror)
Can't Get to Work Cocoapods and Yosemite
In Ruby, What Are the Vertical Lines
Sharing an Enumerator Across Threads
Generate Activerecord Schema from an Existing Table
How to Rescue from a Require "Gem_Name" When the Gem Is Not Installed
MAC Osx Lion and Ruby - [Fatal] Failed to Allocate Memory
Is the .Each Iterator in Ruby Guaranteed to Give the Same Order on the Same Elements Every Time
Session Not Destroyed When Closing Browser - Railstutorial.Org
How to Specify the Location of the Chromedriver Binary
How to Install Rails with Jruby
Command for Displaying a Gem's Dependencies