Reputation: 34884
I know how to run an external process as there are many ways to do so. But how do I capture its output and exit code to the variables? These, the most popular ways of running a process, don't work as I want:
a = `ls -l` # "a" captures only output
b = system "ls -l " # "b" captures only exit code
Upvotes: 2
Views: 733
Reputation: 48599
I want exception as an instance of class Exception to be able to re-raise it, not just a string.
You can do this:
#my_prog.rb
puts 'hello'
10/0
...
require 'open3'
begin
Open3.popen3("ruby my_prog.rb") do |stdin, stdout, stderr, wait_thr|
puts stdout.read
status_obj = wait_thr.value #Process::Status object returned.
puts status_obj.exitstatus
error = stderr.read
md = error.match(/\w+ Error/xm)
if md
e = Exception.const_get(md[0]).new if md
p e.class.ancestors
raise e
end
end
rescue ZeroDivisionError
puts 'Hey, someone divided by zero!'
end
--output:--
hello
1
[ZeroDivisionError, StandardError, Exception, Object, Kernel, BasicObject]
Hey, someone divided by zero!
Unfortunately, there are several exceptions whose names do not end in 'Error'--but you can modify the code to search for those specifically in the error message.
Upvotes: 0
Reputation: 118271
Here is a way to get this out.
#!/usr/bin/env ruby
require 'open3'
Open3.popen3("ls -l") do |stdin, stdout, stderr, wait_thr|
puts stdout.read
puts wait_thr.value.exitstatus
end
# >> total 52
# >> -rw-r--r-- 1 arup users 0 Aug 5 09:32 a.rb
# >> drwxr-xr-x 2 arup users 4096 Jul 20 20:37 FSS
# >> drwxr-xr-x 2 arup users 4096 Jul 20 20:37 fss_dir
# >> -rw-r--r-- 1 arup users 42 Jul 19 01:36 out.txt
# .....
#...
# >> 0
Doco is very clear of ::popen3
. stdout
gives IO
object. So, we need to use IO#read
method. And wait_thr.value
gives us Process::Status
. Now once we have that object, we can use #exitstatus
method for the same.
Upvotes: -1
Reputation: 75488
Most appropriate is to read $?.exitstatus
:
a = `ls -l` # gets output
b = $?.exitstatus # gets exit code
Test:
`true`
# => ""
$?.exitstatus
# => 0
`false`
# => ""
$?.exitstatus
# => 1
$?.class
# => Process::Status
See Process::Status for more ways to handle exit status.
Upvotes: 5
Reputation: 48599
#my_prog.rb
puts 'hello'
exit 10
...
require 'open3'
Open3.popen2("ruby my_prog.rb") do |stdin, stdout, wait_thr|
puts stdout.read
status_obj = wait_thr.value # Process::Status object returned.
puts status_obj.exitstatus
end
--output:--
hello
10
Upvotes: 0
Reputation: 47792
I would have a look at the popen4 gem, as it will allow you to get stout/stderr and the exit status.
Also see this page describing 6 Ways to Run Shell Commands in Ruby which also details popen4 usage.
status = Open4::popen4("false") do |pid, stdin, stdout, stderr|
puts "stdout: #{stdout}"
end
puts status
Upvotes: 1