Here is a ruby 1.9.2 version with close_on_exec=. I leave it as an 
exercise to refactor this to an arbitrary pipeline of N commands - it 
would return one input pipe, one output pipe, N pids and N error pipes.

Regards,

Brian.


#Thread.abort_on_exception = true  # for debugging

ruby_to_a_rd, ruby_to_a_wr = IO.pipe
ruby_to_a_wr.close_on_exec = true # no children should have this

a_to_b_rd, a_to_b_wr = IO.pipe

a_err_rd, a_err_wr = IO.pipe
a_err_rd.close_on_exec = true     # no children should have this

pid1 = fork do
  a_to_b_rd.close
  STDIN.reopen(ruby_to_a_rd)
  STDOUT.reopen(a_to_b_wr)
  STDERR.reopen(a_err_wr)
  exec("cat; echo done cat 1>&2")
  STDERR.puts "Whoops! #{$!}"
end
# we don't want these fds, nor any of the further children
ruby_to_a_rd.close
a_to_b_wr.close
a_err_wr.close

b_to_c_rd, b_to_c_wr = IO.pipe
b_err_rd, b_err_wr = IO.pipe
b_err_rd.close_on_exec = true  # no children should have this

pid2 = fork do
  b_to_c_rd.close
  STDIN.reopen(a_to_b_rd)
  STDOUT.reopen(b_to_c_wr)
  STDERR.reopen(b_err_wr)
  exec("tr 'a-z' 'A-Z'; echo done tr 1>&2")
  STDERR.puts "Whoops! #{$!}"
end
# we don't want these fds, nor any of the further children
a_to_b_rd.close
b_to_c_wr.close
b_err_wr.close

c_to_ruby_rd, c_to_ruby_wr = IO.pipe
c_err_rd, c_err_wr = IO.pipe
c_err_rd.close_on_exec = true  # no children should have this
pid3 = fork do
  c_to_ruby_rd.close
  STDIN.reopen(b_to_c_rd)
  STDOUT.reopen(c_to_ruby_wr)
  STDERR.reopen(c_err_wr)
  exec("sed 's/O/0/g'; echo done sed 1>&2")
  STDERR.puts "Whoops! #{$!}"
end
# we don't want these fds, nor any of the further children
b_to_c_rd.close
c_to_ruby_wr.close
c_err_wr.close

Thread.new do
  ruby_to_a_wr.puts "Here is some data"
  ruby_to_a_wr.puts "And some more"
  ruby_to_a_wr.close
end

Thread.new do
  while line = a_err_rd.gets
    puts "A err: #{line}"
  end
  a_err_rd.close
end

Thread.new do
  while line = b_err_rd.gets
    puts "B err: #{line}"
  end
  b_err_rd.close
end

Thread.new do
  while line = c_err_rd.gets
    puts "C err: #{line}"
  end
  c_err_rd.close
end

while line = c_to_ruby_rd.gets
  puts line
end
c_to_ruby_rd.close

-- 
Posted via http://www.ruby-forum.com/.