Reputation: 287400
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
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
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
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
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
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