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


当前回答

不确定shell命令。我使用以下命令将系统命令的输出捕获到变量val中:

val = capture(:stdout) do
  system("pwd")
end

puts val

缩短版本:

val = capture(:stdout) { system("pwd") }

捕获方法由active_support/core_ext/kernel/reporting.rb提供

类似地,我们也可以用:stderr捕获标准错误

其他回答

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

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

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

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

还有一个选择:

当你:

需要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。

下面是我在OS X上的ruby脚本中使用的一个很酷的脚本(这样我就可以在切换离开窗口后启动脚本并获得更新):

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )

给定像attrib这样的命令:

require 'open3'

a="attrib"
Open3.popen3(a) do |stdin, stdout, stderr|
  puts stdout.read
end

我发现,虽然这种方法不像

system("thecommand")

or

`thecommand`

在反引号中,与其他方法相比,此方法的一个优点是 反勾号似乎不让我把我运行的命令/存储我想要运行的命令在一个变量中,而system(" command")似乎不让我得到输出,而这个方法让我做这两件事,它让我访问stdin, stdout和stderr独立。

参见“在ruby中执行命令”和ruby的Open3文档。

这不是一个真正的答案,但也许有人会发现它有用:

在Windows上使用TK GUI时,您需要从rubyw调用shell命令,您总是会有一个烦人的CMD窗口弹出不到一秒钟。

为了避免这种情况,你可以使用:

WIN32OLE.new('Shell.Application').ShellExecute('ipconfig > log.txt','','','open',0)

or

WIN32OLE.new('WScript.Shell').Run('ipconfig > log.txt',0,0)

两者都将ipconfig输出存储在log.txt中,但是不会弹出窗口。

你需要在你的脚本中要求'win32ole'。

system(), exec()和spawn()都会在使用TK和rubyw时弹出恼人的窗口。