Calling shell commands from Ruby

2018-12-31 04:48发布

How do I call shell commands from inside of a Ruby program? How do I then get output from these commands back into Ruby?

20条回答
刘海飞了
2楼-- · 2018-12-31 05:17

My favourite is Open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
查看更多
春风洒进眼中
3楼-- · 2018-12-31 05:17

Using the answers here and linked in Mihai's answer, I put together a function that meets these requirements:

  1. Neatly captures STDOUT and STDERR so they don't "leak" when my script is run from the console.
  2. Allows arguments to be passed to the shell as an array, so there's no need to worry about escaping.
  3. Captures the exit status of the command so it is clear when an error has occurred.

As a bonus, this one will also return STDOUT in cases where the shell command exits successfully (0) and puts anything on STDOUT. In this manner, it differs from system, which simply returns true in such cases.

Code follows. The specific function is system_quietly:

require 'open3'

class ShellError < StandardError; end

#actual function:
def system_quietly(*cmd)
  exit_status=nil
  err=nil
  out=nil
  Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thread|
    err = stderr.gets(nil)
    out = stdout.gets(nil)
    [stdin, stdout, stderr].each{|stream| stream.send('close')}
    exit_status = wait_thread.value
  end
  if exit_status.to_i > 0
    err = err.chomp if err
    raise ShellError, err
  elsif out
    return out.chomp
  else
    return true
  end
end

#calling it:
begin
  puts system_quietly('which', 'ruby')
rescue ShellError
  abort "Looks like you don't have the `ruby` command. Odd."
end

#output: => "/Users/me/.rvm/rubies/ruby-1.9.2-p136/bin/ruby"
查看更多
登录 后发表回答