Skip to content

Maintenance Ruby 3.3 gets fixes, but no new features. Switch to Ruby 4.0 →

instance method

Open3#popen2e

Open3.popen2e([env, ] command_line, options = {}) → [stdin, stdout_and_stderr, wait_thread]
Open3.popen2e([env, ] exe_path, *args, options = {}) → [stdin, stdout_and_stderr, wait_thread]
Open3.popen2e([env, ] command_line, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } → object
Open3.popen2e([env, ] exe_path, *args, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } → object

Basically a wrapper for Process.spawn that:

  • Creates a child process, by calling Process.spawn with the given arguments.

  • Creates streams stdin, stdout_and_stderr, which are the standard input and the merge of the standard output and standard error streams in the child process.

  • Creates thread wait_thread that waits for the child process to exit; the thread has method pid, which returns the process ID of the child process.

With no block given, returns the array [stdin, stdout_and_stderr, wait_thread]. The caller should close each of the two returned streams.

Example
stdin, stdout_and_stderr, wait_thread = Open3.popen2e('echo')
# => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f7577da4398 run>]
stdin.close
stdout_and_stderr.close
wait_thread.pid   # => 2274600
wait_thread.value # => #<Process::Status: pid 2274600 exit 0>

With a block given, calls the block with the three variables (two streams and the wait thread) and returns the block’s return value. The caller need not close the streams:

Example
Open3.popen2e('echo') do |stdin, stdout_and_stderr, wait_thread|
  p stdin
  p stdout_and_stderr
  p wait_thread
  p wait_thread.pid
  p wait_thread.value
end

Output:

Example
#<IO:fd 6>
#<IO:fd 7>
#<Process::Waiter:0x00007f75777578c8 sleep>
2274763
#<Process::Status: pid 2274763 exit 0>

Like Process.spawn, this method has potential security vulnerabilities if called with untrusted input; see Command Injection.

Unlike Process.spawn, this method waits for the child process to exit before returning, so the caller need not do so.

If the first argument is a hash, it becomes leading argument env in the call to Process.spawn; see Execution Environment.

If the last argument is a hash, it becomes trailing argument options in the call to Process.spawn; see Execution Options.

The single required argument is one of the following:

  • command_line if it is a string, and if it begins with a shell reserved word or special built-in, or if it contains one or more metacharacters.

  • exe_path otherwise.

Argument command_line

String argument command_line is a command line to be passed to a shell; it must begin with a shell reserved word, begin with a special built-in, or contain meta characters:

Example
Open3.popen2e('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
Open3.popen2e('echo') {|*args| p args }                         # Built-in.
Open3.popen2e('date > date.tmp') {|*args| p args }              # Contains meta character.

Output (similar for each call above):

Example
# => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577d8a1f0 dead>]

The command line may also contain arguments and options for the command:

Example
Open3.popen2e('echo "Foo"') { |i, o_and_e, t| o_and_e.gets }
"Foo\n"

Argument exe_path

Argument exe_path is one of the following:

  • The string path to an executable to be called.

  • A 2-element array containing the path to an executable and the string to be used as the name of the executing process.

Example:

Example
Open3.popen2e('/usr/bin/date') { |i, o_and_e, t| o_and_e.gets }
# => "Thu Sep 28 01:58:45 PM CDT 2023\n"

Ruby invokes the executable directly, with no shell and no shell expansion:

Example
Open3.popen2e('doesnt_exist') { |i, o_and_e, t| o_and_e.gets } # Raises Errno::ENOENT

If one or more args is given, each is an argument or option to be passed to the executable:

Example
Open3.popen2e('echo', 'C #') { |i, o_and_e, t| o_and_e.gets }
# => "C #\n"
Open3.popen2e('echo', 'hello', 'world') { |i, o_and_e, t| o_and_e.gets }
# => "hello world\n"

Related:

  • Open3.popen2: Makes the standard input and standard output streams of the child process available as separate streams, with no access to the standard error stream.

  • Open3.popen3: Makes the standard input, standard output, and standard error streams of the child process available as separate streams.

See also .popen2e #popen2 #popen3 #pipeline_w also in 4.1 · 4.0 · 3.4 · 3.2 · 3.1 · 3.0