49

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.

pupeno
  • 267,428
  • 120
  • 345
  • 578

4 Answers4

80

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']
fl00r
  • 81,403
  • 31
  • 214
  • 233
  • 1
    I know those ways of running a command, none of them capture the output into a string and output it at the same time. – pupeno Apr 19 '12 at 09:21
  • I don't see any variant of `system` that takes `out` and `err` parameters? Is this Ruby 2.0? – Matthias Nov 09 '13 at 17:34
  • @Matthias for old ruby you need => ("hash rocket") notation, so: , out: io, err: :out becomes , :out => io, :err => :out – Simon B. Oct 29 '14 at 15:02
  • system("ruby", "-e 3.times{|i| p i; sleep 1}", :out => io, :err => :out) NOT WORKING: in `system': can't convert Hash into String (TypeError) – user180574 Oct 14 '15 at 20:53
  • system with out: and err:, nice! – Rafael Oliveira Oct 24 '15 at 01:34
  • I like the last answer - I did not have the idea of using IO.popen() and .each on it. system() does line-output, whereas default `` backtick waits until it has finished. – shevy Aug 03 '17 at 00:18
15

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.

Community
  • 1
  • 1
0x4a6f4672
  • 25,970
  • 16
  • 101
  • 133
14

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

require 'open3'

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

puts stdout
Kannan S
  • 2,329
  • 16
  • 17
0

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
jayhendren
  • 3,842
  • 1
  • 32
  • 53