在 Ruby 中执行 Shell 命令的 6 种方法
我们时常会与操作系统交互或在 Ruby 中执行 Shell 命令。Ruby为我们提供了完成该任务的诸多方法。
Exec
Kernel#exec通过执行给定的命令来替换当前进程,例如:$ irb
>> exec 'echo "hello $HOSTNAME"'
hello codefun
$
注意
exec利用echo命令替换了irb进程,然后退出。因为 Ruby 实际上结束了该方法,所以只能有限使用。该方法的缺点是,你无法从 Ruby 脚本中知道命令是执行成功还是失败。System
system命令与exec操作相似,但它是在 subshell 中执行,而不是替换当前进程。与exec相比,system给我们更多的信息。如果命令执行成功,它返回 true;否则返回 false。$irb
>> system 'echo "hello $HOSTNAME"'
hello codefun
=> true
>> system 'false'
=> false
>> puts $?
256
=> nil
>>
system将进程的退出状态设置到全局变量$?。注意false命令的退出状态,总是非 0 值。检查退出码让我们既可以抛出(raise)异常,又能够重试(retry)命令。新手注意:Unix 命令执行成功退出码为 0,否则为非 0。
如果我们想知道“命令是否执行成功呢?”,使用
system就很好。然而,我们时常想要捕获命令的输出,并在程序中使用。Backticks (`)
backticks(也叫“backquotes”)在 subshell 中执行命令,并从该命令返回标准输出。
$ irb
>> today = `date`
=> "Wed Jul 4 22:03:15 CST 2012\n"
>> $?
=> #<Process::Status: pid 6169 exit 0>
>> $?.to_i
=> 0
这也许是在 subshell 中执行命令最广为人知的方法。如你所见,它返回了命令的输出,然后我们可以像其他字符串一样使用它。
注意
$?并非是返回状态的整数,而实际是 Process::Status 对象。我们不仅得到了退出状态,而且有进程 ID。Process::Status#to_i返回整数型的退出状态(#to_s返回字符串型的退出状态)。使用 backticks 我们只能获得命令的标准输出(stdout),而不能获得其标准错 误(stderr)。在下面的例子中,我们执行 Perl 脚本来输出字符串到标准错误。
$ irb
>> warning = `perl -e "warn 'dust in the wind'"`
dust in the wind at -e line 1.
=> ""
>> puts warning => nil
注意变量 warning 没有被设置。当我们在 Perl 中执行 warn
时,产生的标准错误输出并没有被 backticks 捕获。IO#popen
IO#popen是在子进程中执行命令的另一种方法。popen给你更多的控制,子进程的标准输入和标准输出都会连接到 IO 对象。$ irb
>> IO.popen("date") { |f| puts f.gets }
Wed Jul 4 22:02:31 CST 2012
=> nil
虽然
IO#popen不错,但是当需要这类细分层次的信息时,我通常使用Open3#popen3。Open3#popen3
Ruby 标准库包含 Open3 类。它易用,并能返回标准输入、标准输出、以及标准 错误。在本例中,让我们使用交互命令
dc。dc 是从标准输入读取的逆波计算器(reverse-polish calculator)。我们先 push 两个数字和一个操作符到堆栈 中。然后我们使用p来打印输出结果。下面我们 push 5、10 及 +,结果标准输出获得了15。$ irb
>> require 'open3'
=> true
>> stdin, stdout, stderr = Open3.popen3('dc')
=> [#<IO:fd 6>, #<IO:fd 7>, #<IO:fd 9>, #<Thread:0x816d46c sleep>]
>> 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"
使用popen3 的缺点是
$?不返回适当的退出状态。$ irb
>> require 'open3'
=> true
>> stdin, stdout, stderr = Open3.popen3('false')
=> [#<IO:fd 8>, #<IO:fd 10>, #<IO:fd 12>, #<Thread:0x8297644 sleep>]
>> $?
=> nil
>> $?.to_i
=> 0
0?false 是假定返回非 0 退出状态。该缺点带我们到 Open4。
Open4#popen4
Open4#popen4是 Ara Howard 创建的 Ruby Gem。它的操作与open3相似,例外是我们能从程序获得退出状态。popen4为 subshell 返回进程 ID,这样我们能从等候的进程获得退出状态。(你需要安装 open4 gem)$ irb
>> require 'open4'
=> true
>> pid, stdin, stdout, stderr = Open4::popen4 "false"
=> [17913, #<IO:fd 6>, #<IO:fd 7>, #<IO:fd 9>]
>> $?
=> nil
>> pid
=> 17913
>> ignored, status = Process::waitpid2 pid
=> [17913, #<Process::Status: pid 17913 exit 1>]
>> status.to_i
=> 256
你也可以作为块来调用
popen4,它将自动等候退出状态。$ irb
>> require 'open4'
=> true
>> status = Open4::popen4("false") do |pid, stdin, stdout, stderr|
?> puts "PID #{pid}"
>> end
PID 18535
=> #<Process::Status: pid 18535 exit 1>
>> puts status
pid 18535 exit 1
=> nil
原文来自 tech.natemurray.com
翻译 dailyrb
许可 CC-by-sa
在 Ruby 中执行 Shell 命令的 6 种方法的更多相关文章
- python中执行shell命令的几个方法小结(转载)
转载:http://www.jb51.net/article/55327.htm python中执行shell命令的几个方法小结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014- ...
- python中执行shell命令的几个方法小结
原文 http://www.jb51.net/article/55327.htm 最近有个需求就是页面上执行shell命令,第一想到的就是os.system, os.system('cat /proc ...
- 每天一个linux命令(62):sh命令 /Linux中执行shell脚本的4种方法总结
bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...
- linux中执行shell命令的几种常用方法
1 切换到shell脚本所在目录执行shell脚本: cd /test/shell ./test.sh 2 以绝对路径的方式执行shell脚本: /test/shell/test.sh 3 直接使用b ...
- Linux中执行shell脚本的4种方法总结
bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...
- Linux中执行shell脚本的4种方法
bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...
- python中执行shell命令的几个方法
1.os.system() a=os.system("df -hT | awk 'NR==3{print $(NF-1)}'") 该命令会在页面上打印输出结果,但变量不会保留结果, ...
- vim中执行shell命令小结
vim中执行shell命令,有以下几种形式 1):!command 不退出vim,并执行shell命令command,将命令输出显示在vim的命令区域,不会改变当前编辑的文件的内容 例如:!ls -l ...
- Python中执行系统命令常见的几种方法--转载
Python中执行系统命令常见的几种方法 Python中执行系统命令常见的几种方法有: (1)os.system # 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息 # 如果再命令行下执 ...
随机推荐
- 使用Lucene对doc、docx、pdf、txt文档进行全文检索功能的实现
转载请注明出处:http://blog.csdn.net/dongdong9223/article/details/76273859 本文出自[我是干勾鱼的博客] 这里讲一下使用Lucene对doc. ...
- Java反射机制的使用
一:反射是什么 JAVA反射机制是在运行状态中,对于任意一个类,都能够获取这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取类信息以及动态调用对象内容就称为jav ...
- 高性能优化规范建议Mysql
Mysql高性能优化规范建议 https://www.cnblogs.com/huchong/p/10219318.html 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据 ...
- 基于http协议的加密传输方案
最近公司需要通过公网与其它平台完成接口对接,但是基于开发时间和其它因素的考虑,本次对接无法采用https协议实现.既然不能用https协议,那就退而求其次采用http协议吧! 那么问题来了!在对接的过 ...
- C语言使用pthread多线程编程(windows系统)二
我们进行多线程编程,可以有多种选择,可以使用WindowsAPI,如果你在使用GTK,也可以使用GTK实现了的线程库,如果你想让你的程序有更多的移植性你最好是选择POSIX中的Pthread函数库,我 ...
- C#多线程编程之:异步事件调用
当一个事件被触发时,订阅该事件的方法将在触发该事件的线程中执行.也就是说,订阅该事件的方法在触发事件的线程中同步执行.由此,存在一个问 题:如果订阅事件的方法执行时间很长,触发事件的线程被阻塞,长时间 ...
- 黄聪:wordpress如何防止发布文章时候自动清除<P>、<br>换行标签
1.安装[TinyMCE Advanced]插件 2.进入[后台]--[设置]--[TinyMCE Advanced]把这个选项勾上保存即可.
- C++ 实例化对象 p->printX()
一.从栈实例化对象 我们首先定义一个类,类的名字叫TV,里面包括两个成员变量,两个成员函数. class TV // 定义一个电视的类TV { public: ]; // 定义类的属性,一个数组 in ...
- [转]MVC 经验总结_序
<appSettings> <add key="vs:EnableBrowserLink" value="false"/> </a ...
- Spring MVC、MyBatis整合文件配置详解
Spring:http://spring.io/docs MyBatis:http://mybatis.github.io/mybatis-3/ Building a RESTful Web Serv ...