Pablo Fernandez
Pablo Fernandez

Reputation: 287400

Running a command from Ruby displaying and capturing the output

Is there some way to run a (shell) command from Ruby displaying but also capturing the output? Maybe with the help of some gem?

What I mean by displaying is not printing it at the end, but as it appears, so the user gets the feedback of what's going on when running slow commands.

Upvotes: 55

Views: 50131

Answers (5)

Craftonix - AA
Craftonix - AA

Reputation: 420

Have a look at the Ruby docs for the non-blocking form of Open3.popen3:

https://ruby-doc.org/stdlib-3.1.2/libdoc/open3/rdoc/Open3.html#method-c-popen3

Although the name "popen3" is not as familiar as the "system()" command, it is currently the recommended method for running system commands from Ruby with several advantages over the system() command. There are several variations in the Open3 class: capture*, pipline*, popen*.

The docs are quite clear, so I won't repeat them here.

Upvotes: 0

jayhendren
jayhendren

Reputation: 4511

If you are willing to explore a solution outside the standard library, you may also use Mixlib::ShellOut to both stream output and capture it:

require 'mixlib/shellout'
cmd = 'while true; do date; sleep 2; done'
so = Mixlib::ShellOut.new(cmd)
so.live_stream = $stdout
so.run_command
out = so.stdout

Upvotes: 0

Kannan S
Kannan S

Reputation: 2489

I used open3 to captured the output of executed shell command from ruby code.

require 'open3'

stdout, stdeerr, status = Open3.capture3("ls")

puts stdout

Upvotes: 18

0x4a6f4672
0x4a6f4672

Reputation: 28245

You can redirect the output

system 'uptime > results.log'

or save the results.

result = `uptime`
result = %x[uptime]

see here. Getting progress information or output in realtime is more complicated, I doubt that there is a simple solution. Maybe it is possible with advanced process management functions such as Open3.popen3. You could also try to use a pseudo terminal with pty and grap the output there.

Upvotes: 16

fl00r
fl00r

Reputation: 83680

You can run system call like this:

`sleep --help`

Or like this

system "sleep --help"

Or

%x{ sleep --help }

In case of system it will print output and return true or nil, other two methods will return output

PS Oh. It is about displaying in real time.

So. You could use something like this:

system("ruby", "-e 100.times{|i| p i; sleep 1}", out: $stdout, err: :out)

To print data in realtime and store it in variable:

output = []
r, io = IO.pipe
fork do
  system("ruby", "-e 3.times{|i| p i; sleep 1}", out: io, err: :out)
end
io.close
r.each_line{|l| puts l; output << l.chomp}
#=> 0
#=> 1
#=> 2
p output
#=> ['0', '1', '2']

Or use popen

output = []
IO.popen("ruby -e '3.times{|i| p i; sleep 1}'").each do |line|
  p line.chomp
  output << line.chomp
end
#=> '0'
#=> '1'
#=> '2'
p output
#=> ['0', '1', '2']

Upvotes: 82

Related Questions