Method: Open3.popen3

Defined in:
lib/open3.rb

.popen3(*cmd, **opts, &block) ⇒ Object

Open stdin, stdout, and stderr streams and start external executable. In addition, a thread to wait for the started process is created. The thread has a pid method and a thread variable :pid which is the pid of the started process.

Block form:

Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
  pid = 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([env,] cmd... [, opts])
pid = wait_thr[:pid]  # pid of the started process
...
stdin.close  # stdin, stdout and stderr should be closed explicitly in this form.
stdout.close
stderr.close
exit_status = wait_thr.value  # Process::Status object returned.

The parameters env, cmd, and opts are passed to Process.spawn. A commandline string and a list of argument strings can be accepted as follows:

Open3.popen3("echo abc") {|i, o, e, t| ... }
Open3.popen3("echo", "abc") {|i, o, e, t| ... }
Open3.popen3(["echo", "argv0"], "abc") {|i, o, e, t| ... }

If the last parameter, opts, is a Hash, it is recognized as an option for Process.spawn.

Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
  p o.read.chomp #=> "/"
}

wait_thr.value waits for the termination of the process. The block form also waits for the process when it returns.

Closing stdin, stdout and stderr does not wait for the process to complete.

You should be careful to avoid deadlocks. Since pipes are fixed length buffers, Open3.popen3(“prog”) {|i, o, e, t| o.read } deadlocks if the program generates too much output on stderr. You should read stdout and stderr simultaneously (using threads or IO.select). However, if you don't need stderr output, you can use Open3.popen2. If merged stdout and stderr output is not a problem, you can use Open3.popen2e. If you really need stdout and stderr output as separate strings, you can consider Open3.capture3.



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/open3.rb', line 84

def popen3(*cmd, **opts, &block)
  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  err_r, err_w = IO.pipe
  opts[:err] = err_w

  popen_run(cmd, opts, [in_r, out_w, err_w], [in_w, out_r, err_r], &block)
end