从Ruby调用Shell命令
如何从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相同,将访问上次系统执行命令的状态。 然后,我们可以访问
exitstatus和
pid`属性:
$?.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上使用。