如何在 Ruby 中临时重定向 stderr?

发布于 2024-10-08 09:07:05 字数 92 浏览 4 评论 0原文

我想在一个块的持续时间内临时重定向 Ruby 脚本中的 stderr,确保在块结束时将其重置为其原始值。

我在 ruby​​ 文档中找不到如何做到这一点。

I'd like to temporarily redirect stderr in a Ruby script for the duration of a block, ensuring that I reset it to its original value at the end of the block.

I had trouble finding how to do this in the ruby docs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

樱花坊 2024-10-15 09:07:05

在 Ruby 中,$stderr 指的是当前使用作为 stderr 的输出流,而 STDERR默认标准错误流。可以很容易地临时将不同的输出流分配给$stderr

require "stringio"

def capture_stderr
  # The output stream must be an IO-like object. In this case we capture it in
  # an in-memory IO object so we can return the string value. You can assign any
  # IO object here.
  previous_stderr, $stderr = $stderr, StringIO.new
  yield
  $stderr.string
ensure
  # Restore the previous value of stderr (typically equal to STDERR).
  $stderr = previous_stderr
end

现在您可以执行以下操作:

captured_output = capture_stderr do
  # Does not output anything directly.
  $stderr.puts "test"
end

captured_output
#=> "test\n"

同样的原理也适用于 $stdoutSTDOUT

In Ruby, $stderr refers to the output stream that is currently used as stderr, whereas STDERR is the default stderr stream. It is easy to temporarily assign a different output stream to $stderr.

require "stringio"

def capture_stderr
  # The output stream must be an IO-like object. In this case we capture it in
  # an in-memory IO object so we can return the string value. You can assign any
  # IO object here.
  previous_stderr, $stderr = $stderr, StringIO.new
  yield
  $stderr.string
ensure
  # Restore the previous value of stderr (typically equal to STDERR).
  $stderr = previous_stderr
end

Now you can do the following:

captured_output = capture_stderr do
  # Does not output anything directly.
  $stderr.puts "test"
end

captured_output
#=> "test\n"

The same principle also works for $stdout and STDOUT.

〆一缕阳光ご 2024-10-15 09:07:05

这是一个更抽象的解决方案(归功于 David Heinemeier Hansson):

def silence_streams(*streams)
  on_hold = streams.collect { |stream| stream.dup }
  streams.each do |stream|
    stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
    stream.sync = true
  end
  yield
ensure
  streams.each_with_index do |stream, i|
    stream.reopen(on_hold[i])
  end
end

用法:

silence_streams(STDERR) { do_something }

Here is a more abstract solution (credit goes to David Heinemeier Hansson):

def silence_streams(*streams)
  on_hold = streams.collect { |stream| stream.dup }
  streams.each do |stream|
    stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
    stream.sync = true
  end
  yield
ensure
  streams.each_with_index do |stream, i|
    stream.reopen(on_hold[i])
  end
end

Usage:

silence_streams(STDERR) { do_something }
等风也等你 2024-10-15 09:07:05

本质上与 @molf 的答案相同,并且具有相同的用法:

require "stringio"
def capture_stderr
  real_stderr, $stderr = $stderr, StringIO.new
  yield
  $stderr.string
ensure
  $stderr = real_stderr
end

它使用 StringIO 更加简洁,并将 $stderr 保留为调用 capture_stderr 之前的内容。

Essentially the same as @molf's answer, and has the same usage:

require "stringio"
def capture_stderr
  real_stderr, $stderr = $stderr, StringIO.new
  yield
  $stderr.string
ensure
  $stderr = real_stderr
end

It uses StringIO very slightly more concisely, and preserves $stderr as whatever it was before capture_stderr was called.

献世佛 2024-10-15 09:07:05

我喜欢 StringIO 的答案。但是,如果您正在调用外部进程,并且 $stderr = StringIO.new 不起作用,您可能会将 stderr 写入临时文件:

require 'tempfile'

def capture_stderr
  backup_stderr = STDERR.dup
  begin
    Tempfile.open("captured_stderr") do |f|
      STDERR.reopen(f)
      yield
      f.rewind
      f.read
    end
  ensure
    STDERR.reopen backup_stderr
  end
end

I like the StringIO answers. But if you are calling an external process, and $stderr = StringIO.new doesn't work, you might write stderr out to a temporary file:

require 'tempfile'

def capture_stderr
  backup_stderr = STDERR.dup
  begin
    Tempfile.open("captured_stderr") do |f|
      STDERR.reopen(f)
      yield
      f.rewind
      f.read
    end
  ensure
    STDERR.reopen backup_stderr
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文