2010-12-16 9 views
43

मैं ब्लॉक की अवधि के लिए अस्थायी रूप से एक रूबी स्क्रिप्ट में stderr को रीडायरेक्ट करना चाहता हूं, यह सुनिश्चित करना कि मैं इसे ब्लॉक के अंत में अपने मूल मान पर रीसेट कर दूं।मैं रूबी में अस्थायी रूप से stderr को कैसे रीडायरेक्ट कर सकता हूं?

मुझे रूबी दस्तावेज़ों में ऐसा करने में परेशानी थी।

+1

संबंधित प्रश्न: http://stackoverflow.com/questions/3018595/how-do लेकिन आप एक बाहरी प्रक्रिया बुला रहे हैं, और $stderr = StringIO.new काम नहीं करता है, तो आप को stderr बाहर एक अस्थायी फ़ाइल के लिए लिख सकते हैं -i-redirect-stderr-and-stdout-to-file-for-a-ruby-script –

उत्तर

61

रूबी में, $stderr, उत्पादन धारा है कि है वर्तमान में stderr के रूप में इस्तेमाल करने के लिए संदर्भित करता है, जबकि 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" 

इसी सिद्धांत भी $stdout और STDOUT के लिए काम करता है।

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

इसे और अधिक संक्षेप में बहुत थोड़ा StringIO का उपयोग करता है, और $ से पहले capture_stderr बुलाया गया था जो कुछ भी यह था के रूप में stderr को बरकरार रखता है:

+0

मैं इसे फ़ंक्शन (RubyVM :: InstructionSequence) पर उपयोग कर रहा हूं जो सी में सीधे stderr (फ़ाइल descriptor 2) को लिखता है। क्या यह इसके लिए काम करेगा? मैं रूबी रनटाइम – horseyguy

+1

@banister द्वारा बुलाए गए निम्न स्तर सी फ़ंक्शन के stderr आउटपुट को दबाने की कोशिश कर रहा हूं: हाँ, इसे काम करना चाहिए; रुबी आंतरिक रूप से '$ stderr' का उपयोग करता है। और यदि किसी भी कारण से यह मामला नहीं है (जो एक बग होगा) तो दुर्भाग्यवश आप अपने रूबी कोड में इसके बारे में कुछ भी करने में सक्षम नहीं होंगे। – molf

+0

यह काम करता है! आश्चर्यजनक! :) धन्यवाद – horseyguy

10

अनिवार्य रूप से एक ही के @ Molf के रूप में जवाब है, और एक ही उपयोग किया है।

+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", इसलिए यह मेरी विंडोज मशीन पर काम नहीं करेगा। आप कभी नहीं जानते कि लोग क्या अजीब वातावरण चल रहे हैं, इसलिए मैं इसके लिए स्ट्रिंग मिलान के खिलाफ अनुशंसा करता हूं। – 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 
संबंधित मुद्दे

 संबंधित मुद्दे