Processes Have Exit Codes

When a process comes to an end it has one last chance to make its mark on the world: its exit code. Every process that exits does so with a numeric exit code (0-255) denoting whether it exited successfully or with an error.

Traditionally, a process that exits with an exit code of 0 is said to be successful. Any other exit code denotes an error, with different codes pointing to different errors.

Though traditionally they’re used to denote different errors, they’re really just a channel for communication. All you need to do is handle the different exit codes that a process may exit with in a way that suits your program and you’ve gotten away from the traditions.

It’s usually a good idea to stick with the ‘0 as success’ exit code tradition so that your programs will play nicely with other Unix tools.

How to Exit a Process

There are several ways you can exit a process in Ruby, each for different purposes.

exit

The simplest way to exit a process is using Kernel#exit. This is also what happens implicitly when your script ends without an explicit exit statement.

# This will exit the program with the success status code (0).
exit
# You can pass a custom exit code to this method
exit 22
# When Kernel#exit is invoked, before exiting Ruby invokes any blocks
# defined by Kernel#at_exit.
at_exit { puts 'Last!' }
exit

will output:

Last!

exit!

Kernel#exit! is almost exactly the same as Kernel#exit, but with two key differences. The first is that it sets an unsuccessful status code by default (1), and the second is that it will not invoke any blocks defined using Kernel#at_exit.

# This will exit the program with a status code 1.
exit!
# You can still pass an exit code.
exit! 33
# This block will never be invoked.
at_exit { puts 'Silence!' }
exit!

abort

Kernel#abort provides a generic way to exit a process unsuccessfully. Kernel#abort will set the exit code to 1 for the current process.

# Will exit with exit code 1.
abort
# You can pass a message to Kernel#abort. This message will be printed
# to STDERR before the process exits.
abort "Something went horribly wrong."
# Kernel#at_exit blocks are invoked when using Kernel#abort.
at_exit { puts 'Last!' }
abort "Something went horribly wrong."

will output:

Something went horribly wrong.
Last!

raise

A different way to end a process is with an unhandled exception. This is something that you never want to happen in a production environment, but it’s almost always happening in development and test environments.

Note that Kernel#raise, unlike the previous methods, will not exit the process immediately. It simply raises an exception that may be rescued somewhere up the stack. If the exception is not rescued anywhere in the codebase then the unhandled exception will cause the process to exit.

Ending a process this way will still invoke any at_exit handlers and will print the exception message and backtrace to STDERR.

# Similar to abort, an unhandled exception will set the exit code to 1.
raise 'hell'