How do I temporarily redirect stderr in Ruby?

horseyguy picture horseyguy · Dec 16, 2010 · Viewed 16.6k times · Source

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.

Answer

molf picture molf · Dec 16, 2010

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.