2

我正在寻找与反引号运算符(``)等效的东西,它能够在 shell 命令执行期间显示输出。

我在另一篇文章中看到了一个解决方案:(从 Ruby 运行命令显示并捕获输出

output = []
IO.popen("ruby -e '3.times{|i| p i; sleep 1}'").each do |line|
  p line.chomp
  output << line.chomp
end
p output

这个解决方案不符合我的需求,因为 $? 在 shell 命令执行后仍然为 nil。我正在寻找的解决方案也应该设置 $? (以另一种方式返回 $?.exitstatus 的值也足够了)

谢谢!

4

2 回答 2

4

首先,我建议使用Open3中的一种方法。

capture3用于我的一个系统,我们需要获取许多命令行应用程序的 STDOUT 和 STDERR 的输出。

如果您需要管道子流程,请尝试popen3其他“管道”命令之一。

下面是一些代码来说明如何使用popen2,它忽略了 STDERR 通道。如果您想跟踪它,请使用popen3

require 'open3'

output = []

exit_status = Open3.popen2(ENV, "ruby -e '3.times{|i| p i; sleep 1}'") { |stdin, stdout, thr|
  stdin.close
  stdout.each_line do |o|
    o.chomp!
    output << o
    puts %Q(Read from pipe: "#{ o }")
  end
  thr.value
}

puts "Output array: #{ output.join(', ') }"
puts "Exit status: #{ exit_status }"

运行输出:

Read from pipe: "0"
Read from pipe: "1"
Read from pipe: "2"
Output array: 0, 1, 2
Exit status: pid 43413 exit 0

示例代码显示了一种方法。

没有必要使用each_line,但它演示了如何逐行读取,直到子流程关闭其 STDOUT。

capture3不接受块;它一直等到子进程关闭其输出并退出,然后返回内容,这在您想要阻塞进程时非常有用。popen2并且popen3有阻塞和非阻塞版本,但我这里只展示非阻塞版本来演示如何读取和输出来自子进程的内容。

于 2013-08-22T12:46:03.770 回答
3

尝试以下操作:

output = []
IO.popen("ruby -e '3.times{|i| p i; sleep 1 }'") do |f|
  f.each do |line|
    p line.chomp
    output << line.chomp
  end
end
p $?

印刷

"0"
"1"
"2"
#<Process::Status: pid 2501 exit 0>

使用open3

require 'open3'

output = []
Open3.popen2("ruby -e '3.times{|i| p i; sleep 1}'") do |stdin,stdout,wait_thr|
  stdout.each do |line|
    p line.chomp
    output << line.chomp
  end
  p wait_thr.value
end
于 2013-08-22T12:39:59.630 回答