2010-12-16 19 views
43

Rubyスクリプトでstderrを一時的にリダイレクトしたい場合は、ブロックの最後に元の値にリセットしてください。Rubyで標準エラー出力を一時的にリダイレクトするにはどうすればよいですか?

ルビーのドキュメントでこれを行う方法がわかりませんでした。 STDERRデフォルト stderrのストリームであるのに対し、Rubyで

+1

関連質問:http://stackoverflow.com/questions/3018595/how-doあなたが外部プロセスを呼び出している、と$stderr = StringIO.newが動作しない場合でも、あなたは一時ファイルに標準エラー出力を書き出すかもしれません-i-redirect-stderr-and-styout-to-a-ruby-script –

答えて

61

$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 

今、あなたは、次の操作を行うことができます

captured_output = capture_stderr do 
    # Does not output anything directly. 
    $stderr.puts "test" 
end 

captured_output 
#=> "test\n" 

同じ原理も$stdoutSTDOUTのために動作します。

+0

私はこれをCのstderr(ファイル記述子2)に直接書き込む関数(RubyVM :: InstructionSequence)で使用しています。これでうまくいくのだろうか?私は、Rubyランタイムによって呼び出される低レベルのC関数の標準エラー出力を抑制しようとしています。 – horseyguy

+1

@banister:はい、うまくいくはずです。 Rubyは '$ stderr'を内部的に使用します。そして、何らかの理由で(バグになる)それが当てはまらない場合、あなたのRubyコードでは残念ながらあなたはそれについて何もすることができません。 – molf

+0

それは動作します!素晴らしい! :) thanks – horseyguy

10

molfの答え@と本質的に同じ、と同じ用法があります。

require "stringio" 
def capture_stderr 
    real_stderr, $stderr = $stderr, StringIO.new 
    yield 
    $stderr.string 
ensure 
    $stderr = real_stderr 
end 

をそれは非常にわずかにより簡潔にStringIOを使用し、capture_stderrが呼び出される前だった何として$の標準エラー出力を保持します。ここで

+0

良い機能強化! – molf

14

は、より抽象的な溶液(クレジットはデイビット・ハインメアー・ハンスソンに行く)です:

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 

は使用方法:

silence_streams(STDERR) { do_something } 
+0

私のRUBY_PLATFORM == "i386-mingw32"なので、これは私のWindowsマシンでは動作しません。人々が奇妙な環境で動いているかも知れないので、このために文字列の照合をお勧めします。 – Nossidge

5

私はのStringIO答えが好き。

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 
関連する問題