Kernel.spawn

Ruby 1.9 comes with new methods to execute a (shell) command, namely Kernel.spawn also available as Process.spawn. In a few words, Kernel.spawn is the powerful tool hidden behind Kernel.`, Kernel.exec, and Kernel.system. If your feeling is that the latter methods, as well as IO.popen are sometimes too restrictive, Kernel.spawn is probably for you.

Note: these methods have not been backported in Ruby 1.8.x, but you can still use them thanks to the sfl gem (source code available on github. Note that the compatibility coverage of the latter gem is far from 100%. Anyway, all examples below are supported by the 2.0 version.

Quick overview

The new spawn method comes with a lot of options set environment variables for the subprocess, change the current directory, redirect file descriptors (i.e. standard input and output), and so on. In all cases it doesn‘t wait for end of the command but returns the pid of the subprocess. Therefore, you'll have to use Process.wait or Process.detach on the resulting pid. Below are listed typical use cases.

Redirecting

By default, standard file descriptors (i.e. standard input, output and error) will be shared with the calling process. Redirecting them is really simple however, as illustrated below. Be warned however that the IO object must be a real IO object. In other words, retrieving the process output via a StringIO will not work properly...

# Use :in for standard input, :out for standard output,
# and :err for standard error
pid = Kernel.spawn("ls -lA", {:out => any_io_object})

# You'll have to wait for the subprocess after that. Remember that 
# wait sets $? to a Process::Status object containing information 
# on that process, including the exit code.
Process.wait pid

Interestingly, you can also redirect to files directly:

# Same comment as in previous example
pid = Kernel.spawn("cat", {:in => "path_to_the_input_file"})

Closing

It may happen that the subprocess is too verbose and interfers with the output of your own process, by printing debuging information on the standard output for example... In this case, you would like to simply close the subprocess output:

# Same comment as in previous example
pid = Kernel.spawn("verbose_call", {:out => :close})

Changing current directory of the callee

Another interesting use case: some sub processes may expect being located in a specific location. Not difficult either:

pid = Kernel.spawn("ls -lA", {:chdir => "/home/blambeau"})

Going further

I've not seen many blog entries about Kernel.spawn, which is the reason I've written this post (more to bring that powerful method to your attention than to be exhaustive). I've covered only a few use cases and options, refer to the official documentation for details. Remember that the sfl gem does not provide 100% coverage, even if examples listed above should work properly using its 2.0 release!