1

In ruby18 I sometimes did the following to get a subprocess with full control:

stdin, @stdin= IO.pipe
@stdout, stdout= IO.pipe
@stderr, stderr= IO.pipe
@pid= fork do
    @stdin.close
    STDIN.close
    stdin.dup
    @stdout.close
    STDOUT.close
    stdout.dup
    @stderr.close
    STDERR.close
    stderr.dup
    exec(...)
end

This does not work in ruby19. The close method for STDIN, STDOUT, STDERR does not close the underlying filedescriptor in ruby19. How do I do this in ruby19.

johannes
  • 7,262
  • 5
  • 38
  • 57
  • You may want to try the stdlib instead of doing all that pipekeeping by hand: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/open3/rdoc/Open3.html http://www.ruby-doc.org/stdlib-1.8.7/libdoc/open3/rdoc/Open3.html – dbenhur Mar 11 '12 at 09:15

2 Answers2

1

Check out Process.spawn, Open3, and the childprocess gem.

I can't tell exactly what you're trying to do there, but you can take control of a child process's IO in many ways.

Using Unix pipes:

readme, writeme = IO.pipe
pid = fork {
    $stdout.reopen writeme
    readme.close
    exec(...)
}

Juggling the IOs with Process.spawn:

pid = spawn(command, :err=>:out)

Or wrapping the process in POpen3:

require 'open3'
include Open3
popen3(RUBY, '-r', THIS_FILE, '-e', 'hello("Open3", true)') do
  |stdin, stdout, stderr|
  stdin.write("hello from parent")
  stdin.close_write
  stdout.read.split("\n").each do |line|
    puts "[parent] stdout: #{line}"
  end
  stderr.read.split("\n").each do |line|
    puts "[parent] stderr: #{line}"
  end

You might also consider Jesse Storimer's Working With Unix Processes. It has a lot of information and his writing style is very easy to read and understand. The book doubles as a reference guide that is somehow more useful than a lot of the actual documentation.


references:

Anthony Michael Cook
  • 1,082
  • 10
  • 16
1

This post shows one way to temporarily replace stdin in Ruby:

begin 
  save_stdin = $stdin        # a dup by any other name 
  $stdin.reopen('/dev/null') # dup2, essentially 
  # do stuff
ensure 
  $stdin.reopen(save_stdin)  # restore original $stdout 
  save_stdin.close           # and dispose of the copy 
end

Since this question is one of the top google hits for “ruby replace stdin,” I hope this will help others looking for how to do that.

andrewdotn
  • 32,721
  • 10
  • 101
  • 130