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

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Ruby中执⾏Linuxshell命令的六种⽅法详解
在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 $?
pid 11845 exit 0
=> nil
> system 'false'
=> false
> puts $?
pid 11858 exit 1
=> nil
>>
system会将进程的退出的状态码赋值给$?,如果程序正常退出,$?的值为0,否则为⾮0。

通过检测退出的状态码我们可以在ruby脚本中抛出异常或者进⾏重试操作。

注:在Unix-like系统中进程的退出状态码以0和⾮0表⽰,0代表成功,⾮0代表失败。

system可以告诉我们命令执⾏是成功还是失败,但是有些时候我们需要得到执⾏命令的输出,并在脚本中使⽤。

显然system ⽆法直接满⾜,需要我们使⽤反引号来实现。

反引号(`)
使⽤反引号是shell中常⽤的获取命令输出内容的⽅法,在ruby中也是可以,⽽且⼀点都需要做改变。

使⽤反引号执⾏命令也会将命令在另⼀个进程中执⾏。

复制代码代码如下:
1.9.3p448 :013 > today = `date`
=> "Sat Nov 15 19:28:55 CST 2014\n"
1.9.3p448 :014 > $?
=> #<Process::Status: pid 11925 exit 0>
1.9.3p448 :015 > $?.to_i
=> 0
1.9.3p448 :016 >
上⾯的⽅法如此简单,我们可以直接对返回的字符串结果进⾏操作。

注意,$?已经不再是上述的那样单纯的退出状态码了,它实际上是⼀个Process::Status对象。

我们从中不仅可以知道进程的退出状态码也可以知道进程的ID。

使⽤$?.to_i会得到退出的状态码,使⽤$?.to_s会得到包含了进程id,退出状态码等信息的字符串。

使⽤反引号的⼀个结果就是我们只能得到标准的输出(stdout)⽽不能得到标准的错误信息(stderr),⽐如下⾯的例⼦,我们执⾏⼀个输出错误字符串的perl脚本。

复制代码代码如下:
$ 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有⼀个缺陷,进程的退出状态没有写⼊到$?中。

复制代码代码如下:
$ irb
>> require "open3"
=> true
>> stdin, stdout, stderr = Open3.popen3('false')
=> [#<IO:0x6f39c0>, #<IO:0x6f3984>, #<IO:0x6f3920>]
>> $?
=> #<Process::Status: pid=26285,exited(0)>
>> $?.to_i
=> 0
为什么是0,false命令执⾏后的退出状态应该是⾮0才对,由于这个缺陷,我们需要了解⼀下Open4
Open4#popen4
Open4#popen4使⽤起来和Open3#popen3差不多,⽽且我们也可以得到程序的退出状态。

popen4还可以返回⼀个⼦进程ID。

你也可以通过Process::waitpid2 加上对应的进程ID获得进程退出状态。

但是前提是要安装open4的gem。

复制代码代码如下:
$ 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。

相关文档
最新文档