Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

  




 

 

Ruby Programming
Previous Page Home Next Page

Spawning New Processes

There are several ways to spawn a separate process; the easiest is to run some command and wait for it to complete. You might find yourself doing this to run some separate command or retrieve data from the host system. Ruby does this for you with the system and backquote methods.

system("tar xzf test.tgz") tar: test.tgz: Cannot open: No such file or directory\ntar: Error is not recoverable: exiting now\ntar: Child returned status 2\ntar: Error exit delayed from previous errors\nfalse
result = `date`
result "Sun Jun  9 00:08:50 CDT 2002\n"

The method Kernel::system executes the given command in a subprocess; it returns true if the command was found and executed properly, false otherwise. In case of failure, you'll find the subprocess's exit code in the global variable $?.

One problem with system is that the command's output will simply go to the same destination as your program's output, which may not be what you want. To capture the standard output of a subprocess, you can use the backquotes, as with `date` in the previous example. Remember that you may need to use String#chomp to remove the line-ending characters from the result.

Okay, this is fine for simple cases---we can run some other process and get the return status. But many times we need a bit more control than that. We'd like to carry on a conversation with the subprocess, possibly sending it data and possibly getting some back. The method IO.popen does just this. The popen method runs a command as a subprocess and connects that subprocess's standard input and standard output to a Ruby IO object. Write to the IO object, and the subprocess can read it on standard input. Whatever the subprocess writes is available in the Ruby program by reading from the IO object.

For example, on our systems one of the more useful utilities is pig, a program that reads words from standard input and prints them in pig Latin (or igpay atinlay). We can use this when our Ruby programs need to send us output that our 5-year-olds shouldn't be able to understand.

pig = IO.popen("pig", "w+")
pig.puts "ice cream after they go to bed"
pig.close_write
puts pig.gets
produces:
iceway eamcray afterway eythay ogay otay edbay

This example illustrates both the apparent simplicity and the real-world complexities involved in driving subprocesses through pipes. The code certainly looks simple enough: open the pipe, write a phrase, and read back the response. But it turns out that the pig program doesn't flush the output it writes. Our original attempt at this example, which had a pig.puts followed by a pig.gets, hung forever. The pig program processed our input, but its response was never written to the pipe. We had to insert the pig.close_write line. This sends an end-of-file to pig's standard input, and the output we're looking for gets flushed as pig terminates.

There's one more twist to popen. If the command you pass it is a single minus sign (``--''), popen will fork a new Ruby interpreter. Both this and the original interpreter will continue running by returning from the popen. The original process will receive an IO object back, while the child will receive nil.

pipe = IO.popen("-","w+")
if pipe
  pipe.puts "Get a job!"
  $stderr.puts "Child says '#{pipe.gets.chomp}'"
else
  $stderr.puts "Dad says '#{gets.chomp}'"
  puts "OK"
end
produces:
Dad says 'Get a job!'
Child says 'OK'

In addition to popen, the traditional Unix calls Kernel::fork , Kernel::exec , and IO.pipe are available on platforms that support them. The file-naming convention of many IO methods and Kernel::open will also spawn subprocesses if you put a ``|'' as the first character of the filename (see the introduction to class IO on page 325 for details). Note that you cannot create pipes using File.new ; it's just for files.
Ruby Programming
Previous Page Home Next Page

 
 
  Published under the terms of the Open Publication License Design by Interspire