重定向时,为什么Ruby的STDERR输出比前面的STDOUT输出来得早?

重定向时,为什么Ruby的STDERR输出比前面的STDOUT输出来得早?,ruby,bash,Ruby,Bash,在bash中,这将按预期顺序提供输出: ruby -e "puts 'one'; raise 'two'" one -e:1:in `<main>': two (RuntimeError) ruby-e“放‘一’;放‘二’” 一 -e:1:in`:2(运行时错误) 但是,如果我将STDERR重定向到STDOUT,我会在输出之前得到错误,这是我不想要的: ruby -e "puts 'one'; raise 'two'" 2>&1 | cat -e:1:in `<

在bash中,这将按预期顺序提供输出:

ruby -e "puts 'one'; raise 'two'"
one
-e:1:in `<main>': two (RuntimeError)
ruby-e“放‘一’;放‘二’”
一
-e:1:in`:2(运行时错误)
但是,如果我将STDERR重定向到STDOUT,我会在输出之前得到错误,这是我不想要的:

ruby -e "puts 'one'; raise 'two'" 2>&1 | cat
-e:1:in `<main>': two (RuntimeError)
one
ruby-e“放‘一’;升起‘二’”2>&1“猫”
-e:1:in`:2(运行时错误)
一

我想将输出重定向到文本文件(其行为方式与上面的
cat
相同),并获取输出和异常,但顺序与在我的终端中查看输出时相同。这可以实现吗?

这是因为标准输出并不总是立即输出,要强制它输出,您可以使用
IO\flush

puts "one"
$>.flush

另一方面,STDERR总是立即输出。

根据毛里西奥和吉尔喜欢玉米饼的回答,我(通过)得出了以下结论:

或者,如果可以修改脚本本身,请将该行添加到开头


谢谢大家!

发生这种情况的原因是行缓冲与块缓冲。您可以控制缓冲的类型,可以在希望其输出同步的点刷新缓冲,也可以等到退出时刷新所有内容。除非以某种方式强制执行,否则缓冲取决于输出是否为tty-type1文件描述符,因此重定向到管道会改变模式

具体而言:

                 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 | cat


应该这样做

STDEER总是打印到流中,而STDOUT通常被缓冲以进行打印。这就是我最终使用它的原因:
IO#如果需要多次刷新缓冲区,则刷新
是一个更好的选择
flush
是单次刷新,
sync
将手柄放下,您必须晃动手柄才能使其停止运行。:-)还是很有帮助的答案。
$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