2012-02-13 58 views
4

我试图设置$ stdout来临时写入文件,然后返回到文件。

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" 

这里是输出。

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 

我不知道为什么$ stdout没有重置为控制台?

+0

我确定有人会喜欢,如果你接受张贴的答案之一,如果这解决了你的问题当然! – user2398029 2012-02-21 02:28:20

回答

6

这个问题可以通过改变前呼吁$stdoutdup解决:

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" 

输出:

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 

下面是我通常打包这个功能集成到一个功能:

# 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 

用法:

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" 

编辑:另一个海报提到,只有在使用纯Ruby代码时才需要使用reopen。上面的函数既可以使用纯Ruby代码,也可以使用写入STDOUT的C扩展。

+0

+1,很好的答案。 – 2012-02-13 02:53:36

+0

thnx。这似乎是一个很好的解决方案,但由于某种原因,我在block_given上得到错误?在方法!! ruby​​1.8.7。接受答案..假设我的代码被搞乱了.. – codeObserver 2012-02-22 01:44:14

+0

我只是在这里钓鱼,但你有没有尝试明确地将该块传递给函数?例如。 'def silence_stdout(log ='/ dev/null',&block)' – user2398029 2012-02-22 03:39:12

3

如果您只是使用Ruby代码,则不需要使用reopenputs和其他Ruby方法将使用当前值$stdout,因此您可以重新分配它。

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" 

你只需要使用reopen,如果你正在做的事情,如创建子进程(例如用fork),并希望孩子的输出到别处去,或者如果你有一个扩展,它直接写入到标准输出,而不全球使用Ruby的$stdout

在你的代码,当你调用reopen要重定向$stdoutold_stdout,因为它们都只是同一个IO对象,这就是为什么你没有得到输出回控制台时分配的引用old_stdout回到stdout

+0

好的答案,但你不需要old_stdout,你可以使用STDOUT。你也打开了你的文件(宠物狗)。 – pguardiario 2012-02-13 03:06:49

+0

@pguardiario是的,我只是对问题代码进行了最小更改,以显示他出错的地方。这当然不是“生产质量”,但希望更好地了解为什么原始代码无法正常工作。 (另外,'$ stdout'可能已经被分配给'STDOUT'以外的东西,因此可能需要使用'old_stdout')。 – matt 2012-02-13 03:11:07