Skip to content

End of Life Ruby 3.2 has reached end of life and gets no more fixes. Switch to Ruby 4.0 →

class method

IO.popen

IO.popen(env = {}, cmd, mode = 'r', **opts) → io
IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } → object

Executes the given command cmd as a subprocess whose $stdin and $stdout are connected to a new stream io.

This method has potential security vulnerabilities if called with untrusted input; see Command Injection.

If no block is given, returns the new stream, which depending on given mode may be open for reading, writing, or both. The stream should be explicitly closed (eventually) to avoid resource leaks.

If a block is given, the stream is passed to the block (again, open for reading, writing, or both); when the block exits, the stream is closed, and the block’s value is assigned to global variable $? and returned.

Optional argument mode may be any valid IO mode. See Access Modes.

Required argument cmd determines which of the following occurs:

  • The process forks.

  • A specified program runs in a shell.

  • A specified program runs with specified arguments.

  • A specified program runs with specified arguments and a specified argv0.

Each of these is detailed below.

The optional hash argument env specifies name/value pairs that are to be added to the environment variables for the subprocess:

Example
IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
  pipe.puts 'puts ENV["FOO"]'
  pipe.close_write
  pipe.gets
end => "bar\n"

Optional keyword arguments opts specify:

Forked Process

When argument cmd is the 1-character string '-', causes the process to fork:

Example
IO.popen('-') do |pipe|
  if pipe
    $stderr.puts "In parent, child pid is #{pipe.pid}\n"
  else
    $stderr.puts "In child, pid is #{$$}\n"
  end
end

Output:

In parent, child pid is 26253
In child, pid is 26253

Note that this is not supported on all platforms.

Shell Subprocess

When argument cmd is a single string (but not '-'), the program named cmd is run as a shell command:

Example
IO.popen('uname') do |pipe|
  pipe.readlines
end

Output:

Example
["Linux\n"]

Another example:

Example
IO.popen('/bin/sh', 'r+') do |pipe|
  pipe.puts('ls')
  pipe.close_write
  $stderr.puts pipe.readlines.size
end

Output:

Example
213

Program Subprocess

When argument cmd is an array of strings, the program named cmd[0] is run with all elements of cmd as its arguments:

Example
IO.popen(['du', '..', '.']) do |pipe|
  $stderr.puts pipe.readlines.size
end

Output:

Example
1111

Program Subprocess with argv0

When argument cmd is an array whose first element is a 2-element string array and whose remaining elements (if any) are strings:

  • cmd[0][0] (the first string in the nested array) is the name of a program that is run.

  • cmd[0][1] (the second string in the nested array) is set as the program’s argv[0].

  • cmd[1..-1] (the strings in the outer array) are the program’s arguments.

Example (sets $0 to ‘foo’):

Example
IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"

Some Special Examples

Example
# Set IO encoding.
IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
  euc_jp_string = nkf_io.read
}

# Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
  ls_result_with_error = io.read
end

# Use mixture of spawn options and IO options.
IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
  ls_result_with_error = io.read
end

 f = IO.popen("uname")
 p f.readlines
 f.close
 puts "Parent is #{Process.pid}"
 IO.popen("date") {|f| puts f.gets }
 IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
 p $?
 IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
   f.puts "bar"; f.close_write; puts f.gets
 }

Output (from last section):

["Linux\n"]
Parent is 21346
Thu Jan 15 22:41:19 JST 2009
21346 is here, f is #<IO:fd 3>
21352 is here, f is nil
#<Process::Status: pid 21352 exit 0>
<foo>bar;zot;

Raises exceptions that IO.pipe and Kernel.spawn raise.

See also .pipe .read .open .readlines also in 4.1 · 4.0 · 3.4 · 3.3 · 3.1 · 3.0