Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Backport of Ruby 1.9's Open3 methods to Ruby 1.8
Branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time


Backport of Ruby 1.9's Open3 methods, for use in Ruby 1.8.


Add this line to your application's Gemfile:

gem 'open3_backport'

And then execute:

$ bundle

Or install it yourself as:

$ gem install open3_backport


For the most part, you can just use Open3 methods the same way you would in Ruby 1.9. However, there is currently no support for setting environment nor passing any of the special options that Process.spawn supports in Ruby 1.9.

Here are some examples that should work fine...

# Block form:
Open3.popen3("echo", "a") do |stdin, stdout, stderr, wait_thr|
  pid = # pid of the started process.
  exit_status = wait_thr.value # Process::Status object returned.

# Non-block form:
stdin, stdout, stderr, wait_thr = Open3.popen3("echo", "a")
pid = wait_thr[:pid]  # pid of the started process.
stdin.close  # stdin, stdout and stderr should be closed explicitly in this form.
exit_status = wait_thr.value  # Process::Status object returned.

Open3.popen3("echo a") {|i, o, e, t| ... }

Open3.popen3("echo", "a") {|i, o, e, t| ... }

Open3.popen2("wc -c") do |i, o, t|
  i.print "answer to life the universe and everything"
  p o.gets #=> "42\n"

Open3.popen2("bc -q") do |i, o, t|
  i.puts "obase=13"
  i.puts "6 * 9"
  p o.gets #=> "42\n"

Open3.popen2("dc") do |i, o, t|
  i.print "42P"
  p #=> "*"

# dot is a command of graphviz.
graph = <<'End'
  digraph g {
    a -> b
layouted_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)

o, e, s = Open3.capture3("echo a; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
p o #=> "a\n"
p e #=> "bar\nbaz\nfoo\n"
p s #=> #<Process::Status: pid 32682 exit 0>

image ="/usr/share/openclipart/png/animals/mammals/sheep-md-v0.1.png", :binmode=>true)
thumnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
if s.success?
  print thumnail

# factor is a command for integer factorization.
o, s = Open3.capture2("factor", :stdin_data=>"42")
p o #=> "42: 2 3 7\n"

# generate x**2 graph in png using gnuplot.
gnuplot_commands = <<"End"
  set terminal png
  plot x**2, "-" with lines
  1 14
  2 1
  3 8
  4 5
image, s = Open3.capture2("gnuplot", :stdin_data=>gnuplot_commands, :binmode=>true)

# capture make log
make_log, s = Open3.capture2e("make")

The following examples do not work yet. Pull requests are welcome!

source = "foo.c"
Open3.popen2e("gcc", "-Wall", source) do |i, oe, t|
  oe.each do |line|
    if /warning/ =~ line
      # ...

Open3.pipeline_rw(["tr", "-dc", "A-Za-z"], ["wc", "-c"]) do |i, o, ts|
  i.puts "All persons more than a mile high to leave the court."
  p o.gets #=> "42\n"

Open3.pipeline_rw("sort", "cat -n") do |stdin, stdout, wait_thrs|
  stdin.puts "foo"
  stdin.puts "bar"
  stdin.puts "baz"
  stdin.close     # send EOF to sort.
  p   #=> "     1\tbar\n     2\tbaz\n     3\tfoo\n"

Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
                 [{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
                 "logresolve") {|o, ts|
  o.each_line {|line|
    # ...

Open3.pipeline_r("yes", "head -10") {|o, ts|
  p      #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
  p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
  p ts[1].value #=> #<Process::Status: pid 24913 exit 0>

Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|i, ts|
  i.puts "hello"

# run xeyes in 10 seconds.
Open3.pipeline_start("xeyes") {|ts|
  sleep 10
  t = ts[0]
  p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>

# convert pdf to ps and send it to a printer.
# collect error message of pdftops and lpr.
pdf_file = "paper.pdf"
printer = "printer-name"
err_r, err_w = IO.pipe
Open3.pipeline_start(["pdftops", pdf_file, "-"],
                     ["lpr", "-P#{printer}"],
                     :err=>err_w) {|ts|
  p # error messages of pdftops and lpr.

fname = "/usr/share/man/man1/ruby.1.gz"
p Open3.pipeline(["zcat", fname], "nroff -man", "less")
#=> [#<Process::Status: pid 11817 exit 0>,
#    #<Process::Status: pid 11820 exit 0>,
#    #<Process::Status: pid 11828 exit 0>]

fname = "/usr/share/man/man1/ls.1.gz"
Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")

# convert PDF to PS and send to a printer by lpr
pdf_file = "paper.pdf"
printer = "printer-name"
Open3.pipeline(["pdftops", pdf_file, "-"],
               ["lpr", "-P#{printer}"])

# count lines
Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")

# cyclic pipeline
r,w = IO.pipe
w.print "ibase=14\n10\n"
Open3.pipeline("bc", "tee /dev/tty", :in=>r, :out=>w)
#=> 14
#   18
#   22
#   30
#   42
#   58
#   78
#   106
#   202

Version History

0.0.3 - Bugfix: Critical performance enhancement.

0.0.2 - Bugfix: Include open3 explicitly before redefining.

0.0.1 - Initial release. No support for setting environment nor passing any of the special options that Process.spawn supports in Ruby 1.9. These methods are not yet implemented: popen2e, pipeline, pipeline_start, pipeline_r, pipeline_w, pipeline_rw.


This gem was written by Chris Johnson for Crossroads Systems, Inc. The code and documentation was copied from the Ruby 1.9.3 stdlib, and then key method implementations were re-written and tested to work in Ruby 1.8.7, while aiming to maintain maximum compatibility with the Ruby 1.9.3 method interfaces. The replacement implementation makes heavy use of the open4 gem.


The important bits of open3_backport are pulled directly from Ruby source, available at Copyrights of all other code in the gem are assigned to the copyright owner of Ruby (Yukihiro Matsumoto).

This gem is available under the same license(s) as Ruby itself (See LICENSE file).


  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request
Something went wrong with that request. Please try again.