ruby输出字符串 - 从Ruby调用Shell命令




ruby用法 (14)

上面的答案已经很不错了,但是我真的很想分享以下摘要文章:“ http://tech.natemurray.com/2007/03/ruby-shell-commands.html

基本上,它告诉我们:

Kernel#exec

exec 'echo "hello $HOSTNAME"'

system$?

system 'false' 
puts $?

反引号(`):

today = `date`

IO#popen

IO.popen("date") { |f| puts f.gets }

Open3#popen3 -stdlib:

require "open3"
stdin, stdout, stderr = Open3.popen3('dc') 

Open4#popen4宝石:

require "open4" 
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]

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


不要忘记使用spawn命令创建后台进程来执行指定的命令。 您甚至可以使用Process类和返回的pid等待其完成:

pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid

pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid

该文档说:此方法与#system类似,但它不等待命令完成。


另一种选择:

当你:

  • 需要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运行。


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

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

您可能需要任何内容​​,从简单的反引号(``),system()和IO.popen到具有IO.pipeIO.select的成熟Kernel.fork / IO.select

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

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


如果您确实需要Bash,请按照“最佳”答案中的注释进行操作。

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

如果需要使用Bash, bash -c "your Bash-only command"在所需的调用方法中插入bash -c "your Bash-only command"

quick_output = system("ls -la")

quick_bash = system("bash -c 'ls -la'")

去测试:

system("echo $SHELL") system('bash -c "echo $SHELL"')

或者,如果您正在运行现有的脚本文件(例如script_output = system("./my_script.sh") ),Ruby 应该遵守shebang,但您始终可以使用system("bash ./my_script.sh")来确保(尽管/bin/sh运行/bin/bash可能会有一些开销,但您可能不会注意到。


您还可以使用反引号运算符(`),类似于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

我最喜欢的是Open3

  require "open3"

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

我认为这是关于在Ruby中运行Shell脚本的最佳文章:“在Ruby http://tech.natemurray.com/2007/03/ruby-shell-commands.html ”。

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

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


最简单的方法是,例如:

reboot = `init 6`
puts reboot

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

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

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

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` ,通常称为反引号– `cmd`

    就像许多其他语言一样,包括Bash,PHP和Perl。

    返回shell命令的结果(即标准输出)。

    文件: http://ruby-doc.org/core/Kernel.html#method-i-60 : http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
  2. 内置语法%x( cmd )

    x字符后是分隔符,可以是任何字符。 如果定界符是字符([{< ,则文字包含直到匹配的分隔符为止的字符,并考虑到嵌套的定界符对。对于所有其他定界符,文字包含直到下次出现分隔符时,允许使用字符串插值#{ ... }

    像反引号一样,返回shell命令的结果(即标准输出)。

    文件: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html : http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

    value = %x( echo 'hi' )
    value = %x[ #{cmd} ]
  3. Kernel#system

    在子shell中执行给定命令。

    如果找到命令并成功运行,则返回true ,否则返回false

    文件: http://ruby-doc.org/core/Kernel.html#method-i-system : http://ruby-doc.org/core/Kernel.html#method-i-system

    wasGood = system( "echo 'hi'" )
    wasGood = system( cmd )
  4. Kernel#exec

    通过运行给定的外部命令来替换当前进程。

    不返回任何值,当前进程将被替换且永远不会继续。

    文件: http://ruby-doc.org/core/Kernel.html#method-i-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

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

$?.exitstatus

有关更多阅读,请参阅:


这并不是一个真正的答案,但也许有人会发现它有用,并且与此有关。

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

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

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

要么

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

两者都将ipconfig的输出存储在'log.txt'中,但是不会出现任何窗口。

require 'win32ole'在脚本中require 'win32ole'

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


这是我在OS X上的ruby脚本中使用的一个很酷的脚本(以便即使从窗口切换后也可以启动脚本并获取更新):

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

  • backticks`方法是从ruby调用shell命令的最简单方法。 它返回shell命令的结果。

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`




interop