与在 Ruby 中获取系统调用的输出类似,我正在运行一个系统命令,但是在这种情况下,我需要在命令执行时输出 STDOUT。
与在 Ruby 中获取系统调用的输出类似,我正在运行一个系统命令,但是在这种情况下,我需要在命令执行时输出 STDOUT。
system
,因为system
不支持这个功能。
然而,这次的解决方案不是使用反引号
,而是使用IO.popen
,该函数返回一个 IO 对象,您可以使用它来读取正在生成的输入。IO.popen('command_to_run') { |io| while (line = io.gets) do puts line end }
。 - Montana Harkin反引号
不是解决方案或推荐的方法呢?我们正在尝试实现从 rails notes
调用中捕获输出的类似功能。谢谢! - Joshua Pinterpopen
会给你一个IO
对象,允许你在输出到达时处理它。 - sepp2k如果有人想要阅读 stdout
和 stderr
:
重要的是要同时读取它们,而不是先读一个再读另一个。因为程序可以轮流并且甚至同时向 stdout
和 stderr
输出。所以,你需要使用线程。事实上这一点甚至不是特定于 Ruby 的。
摘自此处。
require 'open3'
cmd = './packer_mock.sh'
data = {:out => [], :err => []}
# see: https://dev59.com/SXM_5IYBdhLWcg3w9oMA#1162850
Open3.popen3(cmd) do |stdin, stdout, stderr, thread|
# read each stream from a new thread
{ :out => stdout, :err => stderr }.each do |key, stream|
Thread.new do
until (raw_line = stream.gets).nil? do
parsed_line = Hash[:timestamp => Time.now, :line => "#{raw_line}"]
# append new lines
data[key].push parsed_line
puts "#{key}: #{parsed_line}"
end
end
end
thread.join # don't exit until the external process is done
end
这是我的解决方案
def io2stream(shell, &block)
Open3.popen3(shell) do |_, stdout, stderr|
while line = stdout.gets
block.call(line)
end
while line = stderr.gets
block.call(line)
end
end
end
io2stream("ls -la", &lambda { |str| puts str })
以下是捕获系统命令的标准输出的方法:
output = capture(:stdout) do
system("pwd") # your system command goes here
end
puts output
简化版:
output = capture(:stdout) { system("pwd") }
:stderr
来捕获标准错误。
active_support/core_ext/kernel/reporting.rb提供了capture
方法。capture
将被弃用,所以不确定当前支持的方法名是什么。ActiveSupport::Testing
:https://github.com/rails/rails/blob/main/activesupport/lib/active_support/testing/stream.rb - fiedl