Bu problemimi çözmede biraz başarılı oldum. İşte benzer bir sorunu olan birinin bu sayfayı bulması durumunda bazı açıklamalarla birlikte ayrıntılar. Ancak ayrıntıları önemsemiyorsanız, işte kısa cevap :
PTY.spawn'ı aşağıdaki şekilde kullanın (elbette kendi komutunuzla):
require 'pty'
cmd = "blender -b mball.blend -o //renders/ -F JPEG -x 1 -f 1"
begin
PTY.spawn( cmd ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
Ve işte çok fazla ayrıntıyla uzun cevap :
Gerçek sorun, eğer bir süreç kendi stdout'unu açıkça boşaltmazsa, o zaman stdout'a yazılan her şeyin, işlem tamamlanıncaya kadar gerçekte gönderilmek yerine arabelleğe alınıp, IO'yu en aza indirgemek için ( görünüşe göre bu, birçoklarının uygulama detaylarından biridir). C kitaplıkları, iş hacminin daha az sıklıkta IO ile maksimize edilmesi için yapılmıştır). Süreci, stdout'u düzenli olarak temizleyecek şekilde kolayca değiştirebilirseniz, o zaman bu sizin çözümünüz olacaktır. Benim durumumda, bu bir karıştırıcıydı, bu yüzden benim gibi tam bir çaylak için kaynağı değiştirmek için biraz korkutucu.
Ancak bu işlemleri kabuktan çalıştırdığınızda, standart çıktıyı kabuğa gerçek zamanlı olarak gösterirler ve stdout arabelleğe alınmış gibi görünmez. Yalnızca inandığım başka bir süreçten çağrıldığında tamponlanıyor, ancak bir kabukla uğraşılıyorsa, stdout gerçek zamanlı olarak tamponlanmamış olarak görülüyor.
Bu davranış, çıktısı gerçek zamanlı olarak toplanması gereken alt süreç olarak bir yakut süreci ile bile gözlemlenebilir. Sadece aşağıdaki satırı içeren random.rb bir komut dosyası oluşturun:
5.times { |i| sleep( 3*rand ); puts "#{i}" }
Sonra onu çağırmak ve çıktısını döndürmek için bir Ruby betiği:
IO.popen( "ruby random.rb") do |random|
random.each { |line| puts line }
end
Sonucu beklediğiniz gibi gerçek zamanlı olarak almadığınızı göreceksiniz, ancak daha sonra hepsini birden alacaksınız. STDOUT, kendiniz random.rb'yi çalıştırsanız bile, arabelleğe alınmaz. Bu STDOUT.flush
, bloğun içine random.rb'ye bir ifade eklenerek çözülebilir . Ancak kaynağı değiştiremiyorsanız, bunun üzerinde çalışmalısınız. İşlemin dışından onu temizleyemezsiniz.
Alt süreç gerçek zamanlı olarak kabuğa yazdırabiliyorsa, bunu Ruby ile gerçek zamanlı olarak yakalamanın bir yolu olmalıdır. Ve orada. Ruby core'da bulunan PTY modülünü kullanmanız gerektiğine inanıyorum (1.8.6 her durumda). Üzücü olan şey, belgelenmemiş olması. Ama neyse ki bazı kullanım örnekleri buldum.
İlk olarak, PTY'nin ne olduğunu açıklamak için, sözde terminal anlamına gelir . Temel olarak, ruby betiğinin kendisini, komutu bir kabuğa henüz yazmış gerçek bir kullanıcıymış gibi alt işleme sunmasına izin verir. Bu nedenle, yalnızca bir kullanıcı işlemi bir kabuk aracılığıyla başlattığında (bu durumda STDOUT'un arabelleğe alınmaması gibi) meydana gelen herhangi bir değiştirilmiş davranış meydana gelecektir. Başka bir işlemin bu işlemi başlattığını gizlemek, STDOUT'u arabelleğe alınmadığı için gerçek zamanlı olarak toplamanıza olanak tanır.
Bunun, alt öğe olarak random.rb komut dosyasıyla çalışmasını sağlamak için aşağıdaki kodu deneyin:
require 'pty'
begin
PTY.spawn( "ruby random.rb" ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end