I am trying to set $stdout to write to a file temporarily and then back to a file.
test.rb :
old_stdout = $stdout
$stdout.reopen("mytestfile.out",'w+')
puts "this goes in mytestfile"
$stdout= old_stdout
puts "this should be on the console"
$stdout.reopen("mytestfile1.out",'w+')
puts "this goes in mytestfile1:"
$stdout = old_stdout
puts "this should be back on the console"
Here is the output.
ruby test.rb => no output on the console
cat mytestfile.out
this goes in mytestfile
this should be on the console
cat mytestfile1.out
this goes in mytestfile1:
this should be back on the console
I am not sure why $stdout is not getting reset to console ?
This problem can be resolved by calling dup on $stdout before changing it:
old_stdout = $stdout.dup
$stdout.reopen("mytestfile.out",'w+')
puts "this goes in mytestfile"
$stdout = old_stdout.dup
puts "this should be on the console"
$stdout.reopen("mytestfile1.out",'w+')
puts "this goes in mytestfile1:"
$stdout = old_stdout
puts "this should be back on the console"
Output:
ruby test.rb
# => this should be on the console
# => this should be back on the console
cat mytestfile.out
# => this goes in mytestfile
cat mytestfile1.out
# => this goes in mytestfile1
Here's how I usually package this functionality into a function:
# Runs a block of code while blocking stdout.
# Note that /dev/null should be changed to NUL on Windows.
def silence_stdout(log = '/dev/null')
old = $stdout.dup
$stdout.reopen(File.new(log, 'w'))
yield
$stdout = old
end
Usage:
silence_stdout 'mytestfile.out' do
puts "this goes in mytestfile"
end
puts "this should be on the console"
silence_stdout 'mytestfile1.out' do
puts "this goes in mytestfile1"
end
puts "this should be back on the console"
Edit: as another poster mentioned, using reopen is only necessary when working with pure Ruby code. The function above works both with pure Ruby code and when using, for example, C extensions that write to STDOUT.
You don't need to use reopen if you're just using Ruby code. puts and other Ruby methods will use the current value of $stdout so you can just reassign it.
old_stdout = $stdout
$stdout = File.new("mytestfile.out",'w+')
puts "this goes in mytestfile"
$stdout = old_stdout
puts "this should be on the console"
$stdout = File.new("mytestfile1.out",'w+')
puts "this goes in mytestfile1:"
$stdout = old_stdout
puts "this should be back on the console"
You only need to use reopen if you're doing something like creating child processes (e.g. with fork) and want the child's output to go elsewhere, or if you have an extension that writes directly to standard out without using Ruby's $stdout global.
In your code, when you call reopen you are redirecting both $stdout and old_stdout, as they are both just references to the same IO object, which is why you aren't getting output back to the console when you assign old_stdout back to stdout.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With