Why does STDERR output from Ruby happen before STDOUT exits when redirecting?

In bash, this gives the result in the expected order:

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

But if I redirect STDERR to STDOUT, I get an error before exiting, which I don't want:

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

I want to redirect the output to a text file (it behaves the same as cat above), and get both the output and the exceptions, but in the same order as when viewing the output in my terminal. Can this be achieved?

+6
source share
4 answers

This is due to row buffering and block buffering. You can control the type of buffering, you can clear them at the point where you want their output to be synchronized, or you can just wait until you exit, and at that moment everything will turn red. If you do not impose it anyway, buffering depends on whether the output is a tty type file descriptor 1 , so redirecting to the channel changes the mode.

In particular:

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

You can configure them the same way with:

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

My test case:

 $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. See Ttyname (3).
+9
source

This is because STDOUT is not always output immediately, to make it output, you use IO#flush :

 puts "one" $>.flush 

STDERR, on the other hand, always outputs immediately.

+2
source

Based on the answers of MaurΓ­cio and Gir Loves Tacos, I came up with this (via How to enable 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) 

where /tmp/sync.rb contains

 STDOUT.sync=true 

Or, if you can change the script itself, add this line to the beginning.

Thanks!

0
source

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

gotta do it

0
source

Source: https://habr.com/ru/post/906230/


All Articles