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.
我希望在一个块的持续时间内,在Ruby脚本中暂时重定向stderr,确保在块的末尾将其重置为其原始值。
I had trouble finding how to do this in the ruby docs.
我在ruby文档中找不到这样做的方法。
4 个解决方案
#1
61
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
.
在Ruby中,$stderr指的是当前用作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
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
.
同样的原则也适用于$stdout和stdout。
#2
15
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 }
#3
10
Essentially the same as @molf's answer, and has the same usage:
本质上与@molf的答案相同,用法相同:
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.
它非常简洁地使用StringIO,并将$stderr保留为调用capture_stderr之前的值。
#4
5
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:
我喜欢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
#1
61
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
.
在Ruby中,$stderr指的是当前用作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
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
.
同样的原则也适用于$stdout和stdout。
#2
15
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 }
#3
10
Essentially the same as @molf's answer, and has the same usage:
本质上与@molf的答案相同,用法相同:
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.
它非常简洁地使用StringIO,并将$stderr保留为调用capture_stderr之前的值。
#4
5
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:
我喜欢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