J'ai eu un certain succès dans la résolution de ce problème de la mine. Voici les détails, avec quelques explications, au cas où quelqu'un ayant un problème similaire trouve cette page. Mais si vous n'avez pas de soins pour les détails, voici la réponse:
Utilisation PTY.spawn de la manière suivante (avec votre commande, bien sûr):
require 'pty'
cmd = "blender -b mball.blend -o //renders/ -F JPEG -x 1 -f 1"
begin
PTY.spawn( cmd ) do |stdin, stdout, pid|
begin
# Do stuff with the output here. Just printing to show it works
stdin.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
Et voici la réponse longue, avec beaucoup trop de détails:
Le vrai problème semble être que si un processus n'est pas explicitement vider ses stdout, alors tout ce qui est écrit sur la sortie standard est mis en mémoire tampon plutôt que de réellement envoyé, jusqu'à ce que le processus est terminé, de manière à minimiser les IO (ce qui est apparemment un détail d'implémentation de beaucoup de bibliothèques C, fait en sorte que le débit est optimisée grâce à de moins en moins fréquentes IO). Si vous pouvez facilement modifier le processus, de sorte qu'il bouffées de stdout régulièrement, cela pourrait être votre solution. Dans mon cas, c'était blender, donc un peu intimidant pour un noob complet, comme moi, de modifier le code source.
Mais lors de l'exécution de ces processus à partir de la coquille, ils font de l'affichage sur la sortie standard à la coque en temps réel, et la sortie standard (stdout) ne semble pas être mis en mémoire tampon. C'est seulement tampon lorsqu'il est appelé à partir d'un autre processus, je crois, mais si une coquille est en cours de traitement, la sortie standard (stdout) est visible en temps réel, mémoire sans tampon.
Ce comportement peut même être observée avec un rubis processus que le processus de l'enfant dont la sortie doit être collectées en temps réel. Il suffit de créer un script, aléatoire.rb, avec la ligne suivante:
5.times { |i| sleep( 3*rand ); puts "#{i}" }
Ensuite un script ruby à l'appeler et de retour de sa sortie:
IO.popen( "ruby random.rb") do |random|
random.each { |line| puts line }
end
end
Vous verrez que vous n'obtenez pas le résultat en temps réel comme vous vous en doutez, mais tout à la fois par la suite. La sortie standard est en cours de mise en mémoire tampon, même si vous exécutez aléatoire.rb-vous, il n'est pas mis en mémoire tampon. Ce problème peut être résolu par l'ajout d'un STDOUT.flush
déclaration à l'intérieur du bloc dans un ordre aléatoire.rb. Mais si vous ne pouvez pas modifier le code source, vous devez travailler autour de cela. Vous ne pouvez pas le rincer à partir de l'extérieur du processus.
Si le sous-processus peuvent imprimer à coque en temps réel, alors il doit y avoir un moyen de capturer ce avec Ruby en temps réel. Et il y est. Vous devez utiliser le PTY module, inclus dans ruby je crois (1.8.6 de toute façon). Triste, c'est que ce n'est pas documentée. Mais j'ai trouvé quelques exemples de l'utilisation heureusement.
D'abord, pour expliquer ce que PTY est, il est synonyme de pseudo-terminal. Fondamentalement, il permet au script ruby, de se présenter à la sous-processus, comme si c'est un utilisateur réel qui a juste tapé la commande dans un shell. Ainsi, tout changement de comportement qui se produit uniquement lorsqu'un utilisateur a commencé le processus par l'intermédiaire d'un interpréteur de commandes (comme le STDOUT de ne pas être mise en mémoire tampon, dans ce cas). Dissimuler le fait qu'un autre processus a commencé ce processus vous permettant de récupérer la sortie standard (STDOUT) en temps réel, car il n'est pas mis en mémoire tampon.
Pour faire ce travail avec l'aléatoire.rb script, comme l'enfant, essayez le code suivant:
require 'pty'
begin
PTY.spawn( "ruby random.rb" ) do |stdin, stdout, pid|
begin
stdin.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end