2012-01-17 34 views
6

在bash,這給預期順序輸出:當重定向時,爲什麼Ruby的STDERR輸出會在較早的STDOUT輸出之前出現?

ruby -e "puts 'one'; raise 'two'" 
one 
-e:1:in `<main>': two (RuntimeError) 

但是,如果我重定向STDERR到STDOUT,我得到的輸出,這是我不想之前的錯誤:

ruby -e "puts 'one'; raise 'two'" 2>&1 | cat 
-e:1:in `<main>': two (RuntimeError) 
one 

我想將輸出重定向到一個文本文件(其行爲與上面的cat的行爲相同),同時獲得輸出和異常,但與在終端中查看輸出時的順序相同。這可以實現嗎?

+1

STDEER總是打印到流而STDOUT通常緩衝以進行打印。 – 2012-01-17 20:48:48

回答

2

這是因爲STDOUT總是不輸出向右走,用它強制輸出使用IO#flush

puts "one" 
$>.flush 

STDERR,另一方面總是立即輸出。

+0

如果需要多次刷新緩衝區,「IO#flush」是一個更好的選擇。 'flush'是一次單次刷新,'sync'離開了句柄,你必須微動它才能停止運行。 :-) – 2012-01-17 22:18:00

0

基於毛裏西奧的和吉爾愛玉米餅的答案,我想出了這個(通過How to turn on STDOUT.sync in ruby from the command line):

ruby -r "/tmp/sync.rb" -e "puts 'one'; raise 'two'" 2>&1 | cat 
one 
-e:1:in `<main>': two (RuntimeError) 

其中/tmp/sync.rb包含

STDOUT.sync=true 

或者,如果你可以修改腳本本身,將該行添加到開頭。

謝謝!

+0

這是我最終使用它的:https://github.com/henrik/vim-ruby-runner/commit/d4b8cee927a265bbd016a42cf98f570eb33512ad – 2012-01-17 21:16:56

9

發生這種情況是因爲行緩衝與塊緩衝。你可以控制緩衝的類型,你可以在你希望他們的輸出被同步的地方刷新它們,或者你可以等到退出時刷新一切。除非你強迫這種方式,緩衝取決於輸出是否爲tty型文件描述符,因此重定向到管道中會改變模式。

具體做法是:

    true   false 
       ------------- -------------- 
$stdout.tty? line-buffered block-buffered 
$stderr.tty? line-buffered line-buffered 

可以配置它們都以同樣的方式有:

$stdout.sync = $stderr.sync = true # or false, of course 

我的測試用例:

$stdout.sync = $stderr.sync = true 
$stdout.puts 'stdout a' 
sleep 2 
$stdout.puts 'stdout b' 
sleep 2 
$stderr.puts 'stderr a' 
sleep 2 
$stderr.puts 'stderr b' 
sleep 2 


1.見TTYNAME(3 )。

+1

仍然有幫助的答案。 – sashaegorov 2016-01-18 21:12:19

0

ruby -e STDOUT.sync=true -e "puts 'one'; raise 'two'" 2>&1 | cat

應該這樣做

相關問題