56

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.

5 Answers 5

83

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']
Sign up to request clarification or add additional context in comments.

7 Comments

I know those ways of running a command, none of them capture the output into a string and output it at the same time.
I don't see any variant of system that takes out and err parameters? Is this Ruby 2.0?
@Matthias for old ruby you need => ("hash rocket") notation, so: , out: io, err: :out becomes , :out => io, :err => :out
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)
system with out: and err:, nice!
|
19

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

require 'open3'

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

puts stdout

3 Comments

This should be the accepted answer! It gives you 'results' that you can then work with, and it's part of the standard library.
+80 that should do it :)
This does not answer the question: how to both display and capture the output of a long-running command.
16

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.

1 Comment

Thanks. Helped me. Just add the following line, puts result . This will display the result in console.
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

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.