Ich hatte einige Erfolge bei der Lösung dieses Problems von mir. Hier sind die Details, mit einigen Erklärungen, falls jemand mit einem ähnlichen Problem diese Seite findet. Aber wenn Sie sich nicht für Details interessieren, ist hier die kurze Antwort:
Verwenden Sie PTY.Laich in der folgenden Art und Weise (mit Ihrem eigenen Befehl natürlich):
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, dass, wenn ein Prozess doesn zu sein scheint Lege das stdout nicht explizit weg, dann wird alles, was in stdout geschrieben wurde, gepuffert anstatt tatsächlich gesendet, bis der Prozess abgeschlossen ist, um IO zu minimieren (das ist ein Implementierungsdetail von vielen C-Bibliotheken, so dass der Durchsatz maximiert ist durch weniger häufige IO). Wenn Sie den Prozess leicht so ändern können, dass er stdout regelmäßig löscht, dann wäre das Ihre Lösung. In meinem Fall war es Mixer, also ein bisschen einschüchternd für ein komplettes Noob wie mich, um die Quelle zu modifizieren.
Wenn Sie diese Prozesse jedoch über die Shell ausführen, zeigen sie stdout in Echtzeit zur Shell an, und das 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 der Standout in Echtzeit ungepuffert angezeigt.
Dieses Verhalten kann sogar mit einem Ruby-Prozess als Child-Prozess beobachtet werden, dessen Ausgabe in Echtzeit gesammelt werden muss. Erstellen Sie einfach ein Skript, random.rb mit folgenden Zeile:
ein Ruby-Skript Dann ist es zu nennen, und seinen Ausgang zurück:
IO.popen("ruby random.rb") do |random|
random.each { |line| puts line }
end
Sie werden sehen, dass Sie nicht bekommen, das Ergebnis in Echtzeit, wie Sie vielleicht erwarten, aber gleichzeitig auf einmal. STDOUT wird gepuffert, auch wenn Sie random.rb selbst ausführen, wird es nicht gepuffert. Dies kann durch Hinzufügen einer STDOUT.flush
Anweisung innerhalb des Blocks in random.rb gelöst werden. Aber wenn Sie die Quelle nicht ändern können, müssen Sie dies umgehen. Sie können es nicht von außerhalb des Prozesses spülen.
Wenn der Subprozess in Echtzeit in die Shell drucken kann, muss es auch möglich sein, dies mit Ruby in Echtzeit zu erfassen. Und da ist. Sie müssen das PTY-Modul verwenden, das in Ruby-Core enthalten ist (1.8.6 sowieso). Traurig ist, dass es nicht dokumentiert ist. Aber ich habe glücklicherweise einige Beispiele gefunden.
Zuerst, um zu erklären, was PTY ist, steht es für pseudo terminal. Grundsätzlich erlaubt es dem Ruby-Skript, sich dem Unterprozess zu präsentieren, als wäre es ein echter Benutzer, der den Befehl 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). Das Verbergen der Tatsache, dass ein anderer Prozess gestartet wurde, ermöglicht es Ihnen, den STDOUT in Echtzeit zu sammeln, da er nicht gepuffert wird.
Um diese Arbeit mit dem random.rb Skript als Kind zu machen, versuchen Sie den folgenden Code ein:
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 - Schön und gut gemacht! :) –
Das ist so eine gute Antwort. Meinen Tag gerettet. –
Das ist großartig, aber ich glaube, die stdin und stdout Block Parameter sollten vertauscht werden. Siehe: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/pty/rdoc/PTY.html#method-c-spawn –