46
puts "hi"
puts "bye"

到目前为止,我想存储代码的 STDOUT(在这种情况下,嗨 \nbye 到变量中说“结果”并打印它)

puts result

我这样做的原因是我已将 R 代码集成到我的 Ruby 代码中,在 R 代码运行时将其输出提供给 STDOUT,但无法在代码内部访问输出以进行一些评估。对不起,如果这令人困惑。所以“放置结果”行应该给我打招呼。

4

9 回答 9

81

一个方便的函数,用于将标准输出捕获到字符串中......

以下方法是一个方便的通用工具,用于捕获标准输出并将其作为字符串返回。(我经常在单元测试中使用它来验证打印到标准输出的内容。)特别注意使用该ensure子句来恢复 $stdout (并避免惊讶):

def with_captured_stdout
  original_stdout = $stdout  # capture previous value of $stdout
  $stdout = StringIO.new     # assign a string buffer to $stdout
  yield                      # perform the body of the user code
  $stdout.string             # return the contents of the string buffer
ensure
  $stdout = original_stdout  # restore $stdout to its previous value
end

因此,例如:

>> str = with_captured_stdout { puts "hi"; puts "bye"}
=> "hi\nbye\n"
>> print str
hi
bye
=> nil
于 2014-04-01T05:50:29.757 回答
46

将标准输出重定向到 StringIO 对象

您当然可以将标准输出重定向到变量。例如:

# Set up standard output as a StringIO object.
foo = StringIO.new
$stdout = foo

# Send some text to $stdout.
puts 'hi'
puts 'bye'

# Access the data written to standard output.
$stdout.string
# => "hi\nbye\n"

# Send your captured output to the original output stream.
STDOUT.puts $stdout.string

在实践中,这可能不是一个好主意,但至少现在你知道这是可能的。

于 2013-02-20T19:25:54.087 回答
9

如果您的项目中提供了 activesupport,您可以执行以下操作:

output = capture(:stdout) do
  run_arbitrary_code
end

更多信息Kernel.capture可以在这里找到

于 2014-07-01T09:05:29.980 回答
8

您可以通过在反引号中调用您的 R 脚本来做到这一点,如下所示:

result = `./run-your-script`
puts result  # will contain STDOUT from run-your-script

有关在 Ruby 中运行子进程的更多信息,请查看这个 Stack Overflow 问题

于 2013-02-20T18:35:39.093 回答
1

对于大多数实际目的,您可以将任何$stdout响应write, flush,sync和的内容放入sync=其中tty?

在此示例中,我使用来自 stdlib的修改后的队列。

class Captor < Queue

  alias_method :write, :push

  def method_missing(meth, *args)
    false
  end

  def respond_to_missing?(*args)
    true
  end
end

stream = Captor.new
orig_stdout = $stdout
$stdout = stream

puts_thread = Thread.new do
  loop do
    puts Time.now
    sleep 0.5
  end
end

5.times do
  STDOUT.print ">> #{stream.shift}"
end

puts_thread.kill
$stdout = orig_stdout

如果您想积极地对数据采取行动,而不仅仅是在任务完成后查看它,您需要这样的东西。使用 StringIO 或文件将有多个线程尝试同时同步读取和写入的问题。

于 2017-06-09T12:07:53.230 回答
1

Minitest版本:


assert_output如果您需要确保是否生成了一些输出:

assert_output "Registrars processed: 1\n" do
  puts 'Registrars processed: 1'
end

断言输出


或者capture_io如果您确实需要捕获它,请使用:

out, err = capture_io do
  puts "Some info"
  warn "You did a bad thing"
end

assert_match %r%info%, out
assert_match %r%bad%, err

捕获_io

Minitest它本身在任何 Ruby 版本中都可用,从1.9.3

于 2018-10-02T19:49:58.553 回答
1

为 Ruby 代码子进程捕获标准输出(或标准错误)

# capture_stream(stream) { block } -> String
#
# Captures output on +stream+ for both Ruby code and subprocesses
# 
# === Example
#
#    capture_stream($stdout) { puts 1; system("echo 2") }
# 
# produces
# 
#    "1\n2\n"
#
def capture_stream(stream)
  raise ArgumentError, 'missing block' unless block_given?
  orig_stream = stream.dup
  IO.pipe do |r, w|
    # system call dup2() replaces the file descriptor 
    stream.reopen(w) 
    # there must be only one write end of the pipe;
    # otherwise the read end does not get an EOF 
    # by the final `reopen`
    w.close 
    t = Thread.new { r.read }
    begin
      yield
    ensure
      stream.reopen orig_stream # restore file descriptor 
    end
    t.value # join and get the result of the thread
  end
end

我从钟那里得到灵感。

于 2019-08-07T12:47:05.733 回答
0

对于 RinRuby,请知道 R 有capture.output

R.eval <<EOF
captured <- capture.output( ... )
EOF

puts R.captured 
于 2019-01-05T18:24:20.777 回答
-2

感谢@girasquid 的回答。我将其修改为单个文件版本:

def capture_output(string)
  `echo #{string.inspect}`.chomp
end

# example usage
response_body = "https:\\x2F\\x2Faccounts.google.com\\x2Faccounts"
puts response_body #=> https:\x2F\x2Faccounts.google.com\x2Faccounts
capture_output(response_body) #=> https://accounts.google.com/accounts
于 2016-09-28T10:26:43.830 回答