Dologan
Dologan

Reputation: 4784

Redirecting stdout/stderr of spawn() to a string in Ruby

I would like to execute an external process in Ruby using spawn (for multiple concurrent child processes) and collect the stdout or stderr into a string, in a similar way to what can be done with Python's subprocess Popen.communicate().

I tried redirecting :out/:err to a new StringIO object, but that generates an ArgumentError, and temporarily redefining $stdxxx would mix up the outputs of the child processes.

Upvotes: 6

Views: 5788

Answers (4)

TNT
TNT

Reputation: 3620

The most simple and straightforward way seems

require 'open3'

out, err, ps = Open3.capture3("ls")

puts "Process failed with status #{ps.exitstatus}" unless ps.success?

Here we have the outputs as strings.

Upvotes: 0

Robert
Robert

Reputation: 2198

In case you don't like popen, here's my way:

r, w = IO.pipe
pid = Process.spawn(command, :out => w, :err => [:child, :out]) 
w.close

...

pid, status = Process.wait2
output = r.read
r.close

Anyway you can't redirect to a String object directly. You can at most direct it to an IO object and then read from that, just like the code above.

Upvotes: 9

Victor Moroz
Victor Moroz

Reputation: 9225

Why do you need spawn? Unless you are on Windows you can use popen*, e.g. popen4:

require "open4"

pid, p_i, p_o, p_e = Open4.popen4("ls")
p_i.close
o, e = [p_o, p_e].map { |p| begin p.read ensure p.close end }
s = Process::waitpid2(pid).last

Upvotes: 2

Linuxios
Linuxios

Reputation: 35803

From the Ruby docs it seems that you can't, but you can do this:

spawn("ls", 0 => ["/tmp/ruby_stdout_temp", "w"])
stdoutStr=File.read("/tmp/ruby_stdout_temp")

You can also do the same with standard error. Or, if you wan't to do that and don't mind popen:

io=IO.popen("ls")
stdout=io.read

Upvotes: 1

Related Questions