2012-01-17 36 views
6

Trong bash, điều này sẽ cho kết quả theo thứ tự dự kiến:Tại sao đầu ra STDERR từ Ruby đến trước đầu ra STDOUT trước đó khi chuyển hướng?

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

Nhưng nếu tôi chuyển hướng thiết bị lỗi chuẩn để STDOUT, tôi nhận được lỗi trước khi đầu ra, mà tôi không muốn:

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

Tôi muốn chuyển hướng đầu ra đến một tập tin văn bản (nó hoạt động theo cùng một cách như cat ở trên) và có được cả đầu ra và ngoại lệ, nhưng theo thứ tự như khi nhìn vào đầu ra trong thiết bị đầu cuối của tôi. Điều này có thể đạt được?

+1

STDEER luôn in vào trong dòng khi STDOUT thường đệm được in. –

Trả lời

2

Đó là vì STDOUT không phải lúc nào cũng ra ngay lập tức, để buộc nó vào đầu ra bạn sử dụng IO#flush:

puts "one" 
$>.flush 

STDERR mặt khác luôn kết quả đầu ra ngay lập tức.

+0

'IO # flush' là một lựa chọn tốt hơn nếu có nhu cầu xả bộ đệm nhiều hơn một lần. 'flush' là một single-flush,' sync' rời khỏi tay cầm và bạn sẽ phải lắc lư nó để làm cho nó ngừng chạy. :-) –

0

Dựa trên của Maurício và Gir Loves câu trả lời Tacos', tôi đã đưa ra với điều này (thông qua 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) 

nơi /tmp/sync.rb chứa

STDOUT.sync=true 

Hoặc nếu bạn có thể sửa đổi kịch bản gốc, thêm dòng đó vào đầu.

Cảm ơn bạn!

+0

Đây là những gì tôi đã sử dụng nó cho: https://github.com/henrik/vim-ruby-runner/commit/d4b8cee927a265bbd016a42cf98f570eb33512ad –

9

Điều này xảy ra do tính năng đệm theo bộ đệm và chặn khối. Bạn có thể kiểm soát loại đệm, bạn có thể tuôn ra chúng tại điểm mà bạn muốn đầu ra của chúng được đồng bộ hóa, hoặc bạn chỉ có thể đợi cho đến khi thoát ra tại thời điểm đó mọi thứ bị xóa. Trừ khi bạn buộc nó theo cách này hay cách khác, việc đệm phụ thuộc vào đầu ra có phải là mô tả tập tin , do đó việc chuyển hướng vào đường ống sẽ thay đổi chế độ.

Cụ thể:

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

Bạn có thể cấu hình chúng cả hai cùng một cách với:

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

kiểm tra trường hợp của tôi:

$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. Xem ttyname (3).

+1

Câu trả lời vẫn hữu ích. – sashaegorov

0

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

nên làm điều đó

Các vấn đề liên quan