【问题标题】:Running command line commands within Ruby script在 Ruby 脚本中运行命令行命令
【发布时间】:2011-03-10 18:02:07
【问题描述】:

有没有办法通过 Ruby 运行命令行命令?我正在尝试创建一个小的 Ruby 程序,它可以通过“screen”、“rcsz”等命令行程序拨出和接收/发送。

如果我可以将所有这些与 Ruby(MySQL 后端等)结合起来,那就太好了

【问题讨论】:

标签: ruby command-line scripting terminal command-prompt


【解决方案1】:

是的。有几种方法:


a. 使用%x 或'`':

%x(echo hi) #=> "hi\n"
%x(echo hi >&2) #=> "" (prints 'hi' to stderr)

`echo hi` #=> "hi\n"
`echo hi >&2` #=> "" (prints 'hi' to stderr)

这些方法将返回标准输出,并将标准错误重定向到程序的。


b. 使用system

system 'echo hi' #=> true (prints 'hi')
system 'echo hi >&2' #=> true (prints 'hi' to stderr)
system 'exit 1' #=> nil

如果命令成功,此方法返回true。它将所有输出重定向到程序的。


c. 使用exec

fork { exec 'sleep 60' } # you see a new process in top, "sleep", but no extra ruby process. 
exec 'echo hi' # prints 'hi'
# the code will never get here.

用命令创建的进程替换当前进程。


d.(ruby 1.9)使用spawn

spawn 'sleep 1; echo one' #=> 430
spawn 'echo two' #=> 431
sleep 2
# This program will print "two\none".

此方法不等待进程退出并返回PID。


e. 使用IO.popen

io = IO.popen 'cat', 'r+'
$stdout = io
puts 'hi'
$stdout = IO.new 0
p io.read(1)
io.close
# prints '"h"'.

此方法将返回一个IO 对象,该对象代表新进程的输入/输出。这也是目前我所知道的给程序输入的唯一方式。


f. 使用 Open3(在 1.9.2 及更高版本上)

require 'open3'

stdout,stderr,status = Open3.capture3(some_command)
STDERR.puts stderr
if status.successful?
  puts stdout
else
  STDERR.puts "OH NO!"
end

Open3 有几个其他函数可以显式访问两个输出流。它类似于 popen,但允许您访问 stderr。

【讨论】:

  • 奖励技巧:io = IO.popen 'cat > out.log', 'r+';将命令的输出写入“out.log”
  • 每种方法的优缺点是什么。我如何决定使用哪个?使用FileUtils [ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html] 怎么样?
  • 我正在使用 exec 执行 SVN 命令。我不希望 exec 的输出出现在控制台上。我想重定向它,以便可以将其存储为变量并对此进行一些处理。我该怎么做?
  • status.successful?在 ruby​​ 2.4 上不再为我工作,它更改为 status.success? :)
【解决方案2】:

有几种方法可以在 Ruby 中运行系统命令。

irb(main):003:0> `date /t` # surround with backticks
=> "Thu 07/01/2010 \n"
irb(main):004:0> system("date /t") # system command (returns true/false)
Thu 07/01/2010
=> true
irb(main):005:0> %x{date /t} # %x{} wrapper
=> "Thu 07/01/2010 \n"

但如果您需要使用命令的 stdin/stdout 实际执行输入和输出,您可能需要查看专门提供该功能的 IO::popen 方法。

【讨论】:

  • popen 如果您的应用程序只有标准输出,则效果很好。如果你需要更多的交互或者想要对标准输出、标准输入,特别是标准错误做一些不同的事情,你还需要研究 open3:ruby-doc.org/core/classes/Open3.html
【解决方案3】:
 folder = "/"
 list_all_files = "ls -al #{folder}"
 output = `#{list_all_files}`
 puts output

【讨论】:

    【解决方案4】:

    是的,这当然是可行的,但实施方法会有所不同,具体取决于所讨论的“命令行”程序是在“全屏”还是命令行模式下运行。为命令行编写的程序倾向于读取 STDIN 并写入 STDOUT。这些可以在 Ruby 中使用标准的反引号方法和/或 system/exec 调用直接调用。

    如果程序以“全屏”模式(如 screen 或 vi)运行,则方法必须不同。对于这样的程序,您应该寻找“expect”库的 Ruby 实现。这将允许您编写您希望在屏幕上看到的内容以及当您看到这些特定字符串出现在屏幕上时要发送的内容。

    这不太可能是最好的方法,您可能应该查看您想要实现的目标并找到相关的库/gem 来执行此操作,而不是尝试自动化现有的全屏应用程序。例如,“Need assistance with serial port communications in Ruby”处理串行端口通信,如果您想使用您提到的特定程序来实现拨号,这是拨号的前兆。

    【讨论】:

    • 在 Ruby 中使用其内置的 Pty 模块提供了一个简单版本的 Expect。
    【解决方案5】:

    最常用的方法是使用Open3 这是我对上述代码的代码编辑版本,并进行了一些更正:

    require 'open3'
    puts"Enter the command for execution"
    some_command=gets
    stdout,stderr,status = Open3.capture3(some_command)
    STDERR.puts stderr
    if status.success?
      puts stdout
    else
      STDERR.puts "ERRRR"
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-11
      • 2016-07-18
      • 1970-01-01
      • 2012-05-31
      • 2019-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多