Ich habe einige Erfolge bei der Lösung meines Problems erzielt. Hier sind die Details mit einigen Erklärungen, falls jemand mit einem ähnlichen Problem diese Seite findet. Wenn Sie sich jedoch nicht für Details interessieren, finden Sie hier die kurze Antwort :
Verwenden Sie PTY.spawn auf folgende Weise (natürlich mit Ihrem eigenen Befehl):
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
Und hier ist die lange Antwort mit viel zu vielen Details:
Das eigentliche Problem scheint zu sein, dass, wenn ein Prozess seine Standardausgabe nicht explizit löscht, alles, was in Standardausgabe geschrieben wird, gepuffert und nicht tatsächlich gesendet wird, bis der Prozess abgeschlossen ist, um E / A zu minimieren (dies ist anscheinend ein Implementierungsdetail von vielen C-Bibliotheken, die so erstellt wurden, dass der Durchsatz durch weniger häufige E / A maximiert wird. Wenn Sie den Prozess einfach so ändern können, dass er regelmäßig gelöscht wird, ist dies Ihre Lösung. In meinem Fall war es ein Mixer, also ein bisschen einschüchternd für einen kompletten Noob wie mich, die Quelle zu ändern.
Wenn Sie diese Prozesse jedoch über die Shell ausführen, wird stdout in Echtzeit für die Shell angezeigt, und stdout scheint nicht gepuffert zu sein. Es wird nur gepuffert, wenn es von einem anderen Prozess aufgerufen wird, aber wenn eine Shell behandelt wird, wird das Standardout in Echtzeit ungepuffert angezeigt.
Dieses Verhalten kann sogar bei einem Ruby-Prozess als untergeordneter Prozess beobachtet werden, dessen Ausgabe in Echtzeit erfasst werden muss. Erstellen Sie einfach ein Skript, random.rb, mit der folgenden Zeile:
5.times { |i| sleep( 3*rand ); puts "#{i}" }
Dann ein Ruby-Skript, um es aufzurufen und seine Ausgabe zurückzugeben:
IO.popen( "ruby random.rb") do |random|
random.each { |line| puts line }
end
Sie werden sehen, dass Sie das Ergebnis nicht wie erwartet in Echtzeit erhalten, sondern auf einmal danach. STDOUT wird gepuffert, obwohl es nicht gepuffert wird, wenn Sie random.rb selbst ausführen. Dies kann gelöst werden, indem eine STDOUT.flush
Anweisung innerhalb des Blocks in random.rb hinzugefügt wird. Wenn Sie die Quelle jedoch nicht ändern können, müssen Sie dies umgehen. Sie können es nicht von außerhalb des Prozesses spülen.
Wenn der Unterprozess in Echtzeit in eine Shell gedruckt werden kann, muss es eine Möglichkeit geben, dies auch mit Ruby in Echtzeit zu erfassen. Und da ist. Sie müssen das PTY-Modul verwenden, das meiner Meinung nach im Ruby Core enthalten ist (1.8.6 sowieso). Traurige Sache ist, dass es nicht dokumentiert ist. Aber ich habe zum Glück einige Anwendungsbeispiele gefunden.
Um zu erklären, was PTY ist, steht es zunächst für Pseudo-Terminal . Grundsätzlich kann sich das Ruby-Skript dem Unterprozess so präsentieren, als wäre es ein echter Benutzer, der den Befehl gerade in eine Shell eingegeben hat. Daher tritt jedes geänderte Verhalten auf, das nur auftritt, wenn ein Benutzer den Prozess über eine Shell gestartet hat (z. B. wenn STDOUT in diesem Fall nicht gepuffert wird). Wenn Sie die Tatsache verbergen, dass ein anderer Prozess diesen Prozess gestartet hat, können Sie STDOUT in Echtzeit erfassen, da es nicht gepuffert wird.
Versuchen Sie den folgenden Code, damit dies mit dem Skript random.rb als Kind funktioniert:
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