当前位置:首页 >> 脚本专栏

Ruby中执行Linux shell命令的六种方法详解

在Ruby中,执行shell命令是一件不奇怪的事情,Ruby提供了大概6种方法供开发者进行实现。这些方法都很简单,本文将具体介绍一下如何在Ruby脚本中进行调用终端命令。

exec

exec会将指定的命令替换掉当前进程中的操作,指定命令结束后,进程结束。

复制代码 代码如下:
exec 'echo "hello world"'
print 'abc'

执行上述的命令,结果如下,我们可以看到没有abc的输出,可以看出来,在执行echo "hello world"命令后进程就结束了。不会继续执行后面的print 'abc'。

复制代码 代码如下:
ruby testCommand.rb
hello world

使用exec一个头疼的事情就是没有办法知道shell命令执行成功还是失败。

system

system和exec相似,但是system执行的命令不会是在当前进程,而是在一个新创建的进程。system会返回布尔值来表明命令执行结果是成功还是失败。

复制代码 代码如下:
$ irb
> system 'echo "hello $HOSTNAME"'
hello androidyue
 => true
> puts $"codetitle">复制代码 代码如下:
1.9.3p448 :013 > today = `date`
 => "Sat Nov 15 19:28:55 CST 2014\n"
1.9.3p448 :014 > $"codetitle">复制代码 代码如下:
 $ irb
  warning = `perl -e "warn 'dust in the wind'"`
  dust in the wind at -e line 1.
  => ""
  puts warning

  => nil

可以看出,warning并没有得到出错的信息,这就表明反引号无法得到标准错误的信息。

IO#popen

IO#popen也是一种执行命令的方法,其命令也是在另外的进程中执行。使用popen你可以像操作IO对象一样处理标准输入和输出。

复制代码 代码如下:
$ irb
IO.popen("date") { |f| puts f.gets }
Mon Mar 12 18:58:56 PDT 2007
=> nil

Open3#popen3

在标准的Ruby库中还提供了一个Open3。使用这个类我们可以很容易的对标准输入,输出,错误进行处理。这里我们使用一个可以交互的工具dc。dc是一种逆波兰表达式(又叫做后缀表达式,每一运算符都置于其运算对象之后)的计算器,支持从标准输入读取数学表达式。在这个例子中,我们将两个数值和一个操作符进行压栈处理。然后使用p来输出结果。比如我们输入5和10,然后输入+,然后会得到15\n的输出。

复制代码 代码如下:
$ irb
  stdin, stdout, stderr = Open3.popen3('dc')
  => [#<IO:0x6e5474>, #<IO:0x6e5438>, #<IO:0x6e53d4>]
  stdin.puts(5)
  => nil
  stdin.puts(10)
  => nil
  stdin.puts("+")
  => nil
  stdin.puts("p")
  => nil
  stdout.gets
  => "15\n"

使用这个方法,我们不仅可以读取到命令的输出还可以对命令进行输入操作。这个方法对于进行交互操作很方便。通过popen3,我们还可以得到标准的错误信息。

复制代码 代码如下:
  # (irb continued...)
  stdin.puts("asdfasdfasdfasdf")
  => nil
  stderr.gets
  => "dc: stack empty\n"

但是,在ruby 1.8.5中popen3有一个缺陷,进程的退出状态没有写入到$"codetitle">复制代码 代码如下:
$ irb
  require "open3"
  => true
  stdin, stdout, stderr = Open3.popen3('false')
  => [#<IO:0x6f39c0>, #<IO:0x6f3984>, #<IO:0x6f3920>]
  $"codetitle">复制代码 代码如下:
$ irb
  require "open4"
  => true
  pid, stdin, stdout, stderr = Open4::popen4 "false"
  => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
  $?
  => nil
  pid
  => 26327
  ignored, status = Process::waitpid2 pid
  => [26327, #<Process::Status: pid=26327,exited(1)>]
  status.to_i
  => 256