在bash中,这会按预期顺序给出输出:
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
相同)并获得输出和异常,但顺序与查看终端输出时的顺序相同。这可以实现吗?
答案 0 :(得分:9)
这是因为行缓冲与块缓冲。您可以控制缓冲的类型,您可以在希望其输出同步的位置刷新它们,或者您可以等到退出,此时所有内容都会被刷新。除非你以某种方式强制它,否则缓冲取决于输出是否为tty-type 1 文件描述符,因此重定向到管道会改变模式。
具体做法是:
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 :(得分:2)
这是因为STDOUT并不总是立即输出,强制它输出你使用IO#flush
:
puts "one"
$>.flush
另一方面,STDERR总是立即输出。
答案 2 :(得分:0)
根据Maurício和Gir Loves Tacos的回答,我想出了这个(通过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
或者,如果您可以修改脚本本身,请将该行添加到开头。
谢谢!
答案 3 :(得分:0)
ruby -e STDOUT.sync=true -e "puts 'one'; raise 'two'" 2>&1 | cat
应该这样做