推荐在 Ruby 中执行 shell 代码的方法

Open3.popen3 或 Open3.capture3:
Open3 实际上只使用 Ruby 的 spawn 命令,但为你提供了更好的 API。

Open3.popen3

Popen3 在子进程中运行并返回 stdin,stdout,stderr 和 wait_thr。

require 'open3'
stdin, stdout, stderr, wait_thr = Open3.popen3("sleep 5s && ls")
puts "#{stdout.read} #{stderr.read} #{wait_thr.value.exitstatus}"

要么

require 'open3'
cmd = 'git push heroku master'
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  puts "stdout is:" + stdout.read
  puts "stderr is:" + stderr.read
end

将输出: stdout is:stderr is:fatal:不是 git 存储库(或任何父目录):。git

要么

require 'open3'
cmd = 'ping www.google.com'
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  while line = stdout.gets
    puts line
  end
end

将输出:

使用 32 个字节的数据 ping www.google.com [216.58.223.36]:

216.58.223.36 的回复:bytes = 32 time = 16ms TTL = 54
来自 216.58.223.36 的回复:bytes = 32 time = 10ms TTL = 54
来自 216.58 的回复 .223.36:bytes = 32 time = 21ms TTL = 54
来自 216.58.223.36 的回复:bytes = 32 time = 29ms TTL = 54
Ping 统计数据为 216.58.223.36:
数据包:已发送= 4,已接收= 4,已丢失= 0(0%损失),
以毫秒为单位的近似往返时间:
最小值= 10ms,最大值= 29ms,平均值= 19ms

Open3.capture3:

require 'open3'

stdout, stderr, status = Open3.capture3('my_funky_command', 'and', 'some', 'argumants')
if status.success?
  # command completed successfully, do some more stuff
else
  raise "An error occured"
end

要么

Open3.capture3('/some/binary with some args')  

不推荐,但由于额外的开销和壳注入的可能性。

如果命令从 stdin 读取并且你想要为它提供一些数据:

Open3.capture3('my_funky_command', stdin_data: 'read from stdin')  

使用 chdir 运行具有不同工作目录的命令:

Open3.capture3('my_funky_command', chdir: '/some/directory')