2012-02-13 10 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

投稿した回答の1つを受け入れると、誰かが喜んでくれたと思います。 – user2398029

答えて

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、素敵な答え。 –

+0

thnx。これは良い解決策のように思えますが、何らかの理由で私はblock_givenでfalseになるのですか?メソッドで!!! ruby​​1.8.7。答えを受け入れる...どこかで乱されている自分のコードを書いています。 – codeObserver

+0

私はここで釣っていますが、ブロックを明示的に関数に渡そうとしましたか?例えば。 'def silence_stdout(log = '/ dev/null'、&block)' – user2398029

3

Rubyコードを使用している場合は、reopenを使用する必要はありません。 putsなどのRubyメソッドでは、現在の値$stdoutが使用されるため、再割り当てすることができます。

あなたはせずに、標準に直接書き出す拡張子を持っている場合にのみ、あなたは( forkで例えば)子プロセスを作成するような何かをやっている場合 reopenを使用して、子供の出力が別の場所に行きたいする必要がある、または
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" 

Rubyの$stdoutグローバルを使用しています。あなたのコードで

、あなたは、彼らは両方ともあなたが割り当てるときに、あなたが戻ってコンソールに出力を取得されていません理由で同じIOオブジェクトへの参照のみであるため、あなたが、$stdoutold_stdoutの両方をリダイレクトしているreopen呼び出しますold_stdoutに戻るstdoutに戻る。

+0

良い答えですが、old_stdoutは必要ありません.STDOUTを使うことができます。また、あなたはファイルを開いたままにしました(ペットピーブ)。 – pguardiario

+0

@pguardiarioええ、私はちょうど彼が間違っていた場所を示すために質問のコードに最小限の変更を加えました。確かに "生産品質"ではありませんが、なぜ元のコードが機能していなかったのかをよりよく理解できます。 ( '$ stdout'は既に' STDOUT'以外のものに割り当てられているかもしれないので、 'old_stdout'を使う必要があります)。 – matt

関連する問題