J'ai réussi à résoudre ce problème. Voici les détails, avec quelques explications, au cas où quelqu'un ayant un problème similaire trouve cette page. Mais si vous ne vous souciez pas des détails, voici la réponse courte:
Utilisez PTY.spawn de la manière suivante (avec votre propre commande bien sûr):
require 'pty'
cmd = "blender -b mball.blend -o //renders/ -F JPEG -x 1 -f 1"
begin
PTY.spawn(cmd) do |stdout, stdin, pid|
begin
# Do stuff with the output here. Just printing to show it works
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
Et est ici la réponse longue, avec beaucoup trop de détails:
La vraie question semble être que si un processus doesn « t rincer explicitement son stdout, alors quoi que ce soit par écrit à SDOUT tamponne plutôt que réellement envoyé, jusqu'à ce que le processus se fait, de manière à minimiser IO (ce qui est apparemment un détail de mise en œuvre de nombreuses bibliothèques C, en sorte que le débit est maximisé par des entrées-sorties moins fréquentes). Si vous pouvez facilement modifier le processus afin qu'il vide régulièrement stdout, alors ce serait votre solution. Dans mon cas, c'était blender, donc un peu intimidant pour un noob complet comme moi de modifier la source.
Mais lorsque vous exécutez ces processus à partir du shell, ils affichent stdout à la coquille en temps réel, et le stdout ne semble pas être en mémoire tampon. Il n'est tamponné que lorsqu'il est appelé depuis un autre processus, mais si un shell est traité, le fichier stdout est vu en temps réel, sans tampon.
Ce comportement peut même être observé avec un processus de rubis que le processus de l'enfant dont la sortie doit être collectée en temps réel. Il suffit de créer un script, random.rb, avec la ligne suivante:
Ensuite, un script Ruby pour appeler et retourner sa sortie:
IO.popen("ruby random.rb") do |random|
random.each { |line| puts line }
end
Vous verrez que vous ne recevez pas le résultat en temps réel comme vous pourriez vous y attendre, mais tout de suite après. STDOUT est en cours de tamponnage, même si vous exécutez random.rb vous-même, il n'est pas mis en mémoire tampon. Cela peut être résolu en ajoutant une instruction STDOUT.flush
à l'intérieur du bloc dans random.rb. Mais si vous ne pouvez pas changer la source, vous devez contourner ce problème. Vous ne pouvez pas le vider de l'extérieur du processus.
Si le sous-processus peut imprimer à débourser en temps réel, alors il doit y avoir un moyen de capturer cela avec Ruby en temps réel aussi bien. Et voici. Vous devez utiliser le module PTY, inclus dans le noyau de ruby je crois (1.8.6 de toute façon). Ce qui est triste, c'est que ce n'est pas documenté. Mais j'ai trouvé quelques exemples d'utilisation heureusement.
Tout d'abord, pour expliquer ce que PTY est, il est synonyme de pseudo terminal. Fondamentalement, il permet au script ruby de se présenter au sous-processus comme s'il s'agissait d'un utilisateur réel qui vient de taper la commande dans un shell. Ainsi, tout comportement altéré qui se produit uniquement lorsqu'un utilisateur a démarré le processus via un shell (tel que le STDOUT n'étant pas mis en mémoire tampon, dans ce cas) se produira. Cacher le fait qu'un autre processus a commencé ce processus vous permet de collecter le STDOUT en temps réel, car il n'est pas tamponné.
Pour faire ce travail avec le script random.rb que l'enfant, essayez le code suivant:
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
+1 - Agréable et bien fait! :) –
C'est une bonne réponse. Fait ma journée. –
C'est génial, mais je crois que les paramètres du bloc stdin et stdout devraient être permutés. Voir: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/pty/rdoc/PTY.html#method-c-spawn –