从Ruby调用Shell命令

时间:2020-03-05 18:37:43  来源:igfitidea点击:

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

解决方案

回答

我绝对不是Ruby专家,但我会给我们一个机会:

$ irb 
system "echo Hi"
Hi
=> true

我们还应该能够执行以下操作:

cmd = 'ls'
system(cmd)

回答

我们还可以使用反引号运算符(`),类似于Perl:

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

如果我们需要简单的东西,则非常方便。

我们要使用哪种方法取决于我们要完成的工作。检查文档以获取有关不同方法的更多详细信息。

回答

我喜欢这样做的方法是使用%x字面量,这使得在命令中使用引号变得容易(并且易于阅读!),如下所示:

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

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

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

回答

此说明基于我的一个朋友的注释Ruby脚本。如果要改进脚本,请随时在链接上进行更新。

首先,请注意,当Ruby调用shell时,通常调用/ bin / sh,而不是Bash。在所有系统上,/ bin / sh都不支持某些Bash语法。

以下是执行Shell脚本的方法:

cmd = "echo 'hi'" # Sample string that can be used
  • " Kernel#",通常称为反引号" cmd"。这与许多其他语言一样,包括Bash,PHP和Perl。返回shell命令的结果。文件:http://ruby-doc.org/core/Kernel.html#method-i-60
value = `echo 'hi'`
value = `#{cmd}`
  • 内置语法,x字符后的%x(cmd)是分隔符,可以是任何字符。如果定界符是字符([[、、 {{或者<)之一,则文字会包含直到匹配的分隔符为止的字符,并考虑嵌套的定界符对。对于所有其他定界符,文字包含直到下一个分隔符出现的字符。允许字符串插值#{...}`。返回shell命令的结果,就像反引号一样。Docs:http://www.ruby -doc.org/docs/ProgrammingRuby/html/language.html
value = %x( echo 'hi' )
value = %x[ #{cmd} ]
  • Kernel#system在子shell中执行给定的命令。如果找到命令并成功运行,则返回" true",否则返回" false"。文件:http://ruby-doc.org/core/Kernel.html#method-i-system
wasGood = system( "echo 'hi'" )
wasGood = system( cmd )
  • Kernel#exec通过运行给定的外部命令来替换当前进程。不返回任何值,当前进程将被替换且永远不会继续。文件:http://ruby-doc.org/core/Kernel.html#method-i-exec
exec( "echo 'hi'" )
exec( cmd ) # Note: this will never be reached because of the line above

这里有一些额外的建议:
如果使用反引号system()或者%x {},$?与$ CHILD_STATUS相同,将访问上次系统执行命令的状态。 然后,我们可以访问exitstatuspid`属性:

$?.exitstatus

有关更多阅读,请参阅:

  • http://www.elctech.com/blog/i-m-in-ur-commandline-executin-ma-commands
  • http://blog.jayfields.com/2006/06/ruby-kernel-system-exec-and-x.html
  • http://tech.natemurray.com/2007/03/ruby-shell-commands.html

回答

在这些机制之间进行选择时,需要考虑以下几点:

  • 我们只需要stdout还是需要stderr?甚至分开?
  • 输出多少?我们是否要将整个结果保存在内存中?
  • 我们是否想在子进程仍在运行时读取一些输出?
  • 我们需要结果代码吗?
  • 我们是否需要一个代表过程的红宝石对象,并允许我们按需将其杀死?

我们可能需要任何东西,从简单的反引号(``),system()和IO.popen到成熟的带有IO.pipe和IO.select的Kernel.fork/Kernel.exec

如果子流程执行时间过长,我们可能还想将超时投入混合。

不幸的是,这在很大程度上取决于。

回答

我认为这是关于在Ruby中运行Shell脚本的最佳文章:"在Ruby中运行Shell命令的6种方法"。

如果只需要获取输出,请使用反引号。

我需要更高级的东西,例如STDOUT和STDERR,所以我使用了Open4 gem。我们已在此处说明了所有方法。

回答

我最喜欢的是Open3

require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }

回答

另一种选择:

当你:

  • 需要stderr以及stdout
  • 无法/不会使用Open3 / Open4(它们在Mac上的NetBeans中抛出异常,不知道为什么)

我们可以使用外壳重定向:

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上使用。