如何从Ruby程序内部调用shell命令?然后如何将这些命令的输出返回到Ruby中?


当前回答

使用这里的答案和Mihai的答案链接,我组合了一个满足这些要求的函数:

整洁地捕获STDOUT和STDERR,因此当我的脚本从控制台运行时,它们不会“泄漏”。 允许参数作为数组传递给shell,因此不需要担心转义。 捕获命令的退出状态,以便在发生错误时显示出来。

作为奖励,当shell命令成功退出(0)并将任何内容放在STDOUT上时,该命令还将返回STDOUT。在这种情况下,它与system不同,后者在这种情况下只返回true。

代码如下。具体的函数是system_quiet:

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"

其他回答

我绝对不是Ruby专家,但我还是会试一试:

$ irb 
system "echo Hi"
Hi
=> true

你还应该能够做以下事情:

cmd = 'ls'
system(cmd)

你也可以使用反勾操作符('),类似于Perl:

directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory

如果你需要简单的东西,很方便。

你想要使用哪种方法取决于你想要完成什么;有关不同方法的更多细节,请查看文档。

还有一个选择:

当你:

需要stderr和stdout 不能/不会使用Open3/Open4(他们在我的Mac上的NetBeans中抛出异常,不知道为什么)

你可以使用shell重定向:

puts %x[cat bogus.txt].inspect
  => ""

puts %x[cat bogus.txt 2>&1].inspect
  => "cat: bogus.txt: No such file or directory\n"

从MS-DOS的早期开始,2>&1语法就适用于Linux、Mac和Windows。

我喜欢的方法是使用%x文字,这使得在命令中使用引号很容易(而且易读!),如下所示:

directorylist = %x[find . -name '*test.rb' | sort]

在这种情况下,它将填充当前目录下的所有测试文件的文件列表,您可以按照预期进行处理:

directorylist.each do |filename|
  filename.chomp!
  # work with file
end

最简单的方法是:

reboot = `init 6`
puts reboot