我们时常会与操作系统交互或在 Ruby 中执行 Shell 命令。Ruby为我们提供了完成该任务的诸多方法。

  1. Exec

    Kernel#exec 通过执行给定的命令来替换当前进程,例如:

    $ irb
    >> exec 'echo "hello $HOSTNAME"'
    hello codefun
    $

    注意 exec 利用 echo 命令替换了 irb 进程,然后退出。因为 Ruby 实际上结束了该方法,所以只能有限使用。该方法的缺点是,你无法从 Ruby 脚本中知道命令是执行成功还是失败。

  2. 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 就很好。然而,我们时常想要捕获命令的输出,并在程序中使用。

  3. 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 捕获。

  4. 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

  5. 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。

  6. 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 种方法的更多相关文章

  1. python中执行shell命令的几个方法小结(转载)

    转载:http://www.jb51.net/article/55327.htm python中执行shell命令的几个方法小结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014- ...

  2. python中执行shell命令的几个方法小结

    原文 http://www.jb51.net/article/55327.htm 最近有个需求就是页面上执行shell命令,第一想到的就是os.system, os.system('cat /proc ...

  3. 每天一个linux命令(62):sh命令 /Linux中执行shell脚本的4种方法总结

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...

  4. linux中执行shell命令的几种常用方法

    1 切换到shell脚本所在目录执行shell脚本: cd /test/shell ./test.sh 2 以绝对路径的方式执行shell脚本: /test/shell/test.sh 3 直接使用b ...

  5. Linux中执行shell脚本的4种方法总结

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...

  6. Linux中执行shell脚本的4种方法

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...

  7. python中执行shell命令的几个方法

    1.os.system() a=os.system("df -hT | awk 'NR==3{print $(NF-1)}'") 该命令会在页面上打印输出结果,但变量不会保留结果, ...

  8. vim中执行shell命令小结

    vim中执行shell命令,有以下几种形式 1):!command 不退出vim,并执行shell命令command,将命令输出显示在vim的命令区域,不会改变当前编辑的文件的内容 例如:!ls -l ...

  9. Python中执行系统命令常见的几种方法--转载

    Python中执行系统命令常见的几种方法 Python中执行系统命令常见的几种方法有: (1)os.system # 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息 # 如果再命令行下执 ...

随机推荐

  1. Jenkins使用Git Parameter插件打包

    一. 下载Git Parameter插件: 二. 项目配置: Shell脚本: #!/bin/bash -l echo $deploy_envcase $deploy_env in deploy) e ...

  2. SQL优化(3):使用explain了解SQL性能-part2

    接上文,上文对type列用实例做了说明,本文对Extra列进行一些说明. Extra列 Using filesort 前文说,需要对所有的查询结果进行一次排序,例如当使用order by时.但是若查询 ...

  3. Git 将代码恢复到一个历史的版本

    Git 将代码恢复到一个历史的版本 要把代码回到某个历史版本 比如 test有两种方法 暴力的方式 如果你的仓库是自己在用(不影响别人),那么你可以使用 git reset --hard <ta ...

  4. DesignPattern(四)结构型模式(下)

    上篇链接  https://www.cnblogs.com/qixinbo/p/9023764.html 继续介绍最后三种结构型模式 外观模式 外观模式,也称作 ”门面“模式,在系统中,客户端经常需要 ...

  5. test20181018 B君的第一题

    题意 分析 考场爆零做法 考虑dp,用\(f(i,j,0/1)\)表示i及其子树中形成j个边连通块的方案数,其中i是否向外连边. \(O(n^3)\),转移方程太复杂就打挂了. #include< ...

  6. graphql cli 开发graphql api flow

    作用 代码生成 schema 处理 脚手架应用创建 项目管理 安装cli npm install -g graphql-cli 初始化项目(使用.graphqlconfig管理) 以下为demo de ...

  7. poj3311 经典tsp问题

    题目的大概意思就是一个人到一些城市送披萨,要求找到一条路径可以遍历每个城市后返回出发点,而且路径距离最短.最后输出最短距离就可以. 注意:每个城市可反复訪问多次. 因为题中明白说了两个城市间的直接可达 ...

  8. System.IO.Path类

    System.IO.Path为路径的操作封装了很多很有的东西,利用该类提供的方法能够快速处理路径操作的问题.下面详细了解一下. 1.属性 属性太复杂了,反映什么系统平台的信息,看不懂,等以后看得懂了再 ...

  9. OGNL遍历list、map的常用三种方法

    package com.mylife.po; public class User { private String uname; private String pwd; public String g ...

  10. bzoj4591 [Shoi2015]超能粒子炮·改

    Description 曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加 强大的粒子流的神秘装置.超能粒子炮·改相比超能粒子炮,在威 ...