Method: IO.popen
- Defined in:
- io.c
.popen(env = {}, cmd, mode = 'r', **opts) ⇒ IO .popen(env = ) { ... } ⇒ 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:
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:
-
Options for Kernel#spawn.
Forked Process
When argument cmd is the 1-character string '-', causes the process to fork:
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:
IO.popen('uname') do |pipe|
pipe.readlines
end
Output:
["Linux\n"]
Another example:
IO.popen('/bin/sh', 'r+') do |pipe|
pipe.puts('ls')
pipe.close_write
$stderr.puts pipe.readlines.size
end
Output:
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:
IO.popen(['du', '..', '.']) do |pipe|
$stderr.puts pipe.readlines.size
end
Output:
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’sargv[0]. -
cmd[1..-1](the strings in the outer array) are the program’s arguments.
Example (sets $0 to ‘foo’):
IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
Some Special Examples
# 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.
7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 |
# File 'io.c', line 7982
static VALUE
rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
{
VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
switch (argc) {
case 2:
pmode = argv[1];
case 1:
pname = argv[0];
break;
default:
{
int ex = !NIL_P(opt);
rb_error_arity(argc + ex, 1 + ex, 2 + ex);
}
}
return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
}
|