2012-01-17 12 views
6

En bash, esto da la salida en el orden esperado:¿Por qué la salida STDERR de Ruby aparece antes de la salida STDOUT anterior cuando se redirige?

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

Pero si puedo redirigir STDERR a STDOUT, me sale el error antes de la salida, que no quiero:

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

Quiero redirigir la salida a un archivo de texto (se comporta de la misma manera que en el cat anterior) y obtener salidas y excepciones, pero en el mismo orden que cuando miro la salida en mi terminal. ¿Se puede lograr esto?

+1

STDEER siempre se imprime en la corriente, mientras que la salida estándar generalmente se tampona a imprimir. –

Respuesta

2

Es porque la salida estándar no siempre la salida de inmediato, para forzarlo a utilizar de salida que IO#flush:

puts "one" 
$>.flush 

STDERR por el contrario siempre imprime de forma inmediata.

+0

'IO # flush' es una mejor opción si hay una necesidad de enjuagar el buffer más de una vez. 'flush' es un single-flush,' sync' deja el manejador y tendrás que sacudirlo para que deje de funcionar. :-) –

0

Sobre la base de Maurício de y GIR ama respuestas Tacos', me ocurrió con este (a través de 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) 

donde /tmp/sync.rb contiene

STDOUT.sync=true 

O si se puede modificar el script en sí, agrega esa línea al principio.

¡Gracias!

+0

Esto es lo que terminé utilizándolo: https://github.com/henrik/vim-ruby-runner/commit/d4b8cee927a265bbd016a42cf98f570eb33512ad –

9

Esto ocurre debido a la línea de almacenamiento en búfer vs bloque de almacenamiento en búfer. Puede controlar el tipo de almacenamiento en búfer, puede descargarlos en el punto donde desea que se sincronice su salida, o simplemente puede esperar hasta la salida en que punto todo se vacía. A menos que lo fuerce de una forma u otra, el almacenamiento en búfer depende de si la salida es un descriptor de archivo de tipo tty , por lo que la redirección a una tubería cambia el modo.

Específicamente:

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

Puede configurar los dos de la misma manera con:

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

Mi caso de prueba:

$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. Véase ttyname (3)

+1

Aún así es útil la respuesta. – sashaegorov

0

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

debe hacerlo

Cuestiones relacionadas