이 문제를 성공적으로 해결했습니다. 다음은 유사한 문제가있는 사람이이 페이지를 찾을 수 있도록 몇 가지 설명과 함께 세부 정보입니다. 그러나 세부 사항을 신경 쓰지 않는다면 여기에 짧은 대답이 있습니다 .
다음과 같은 방식으로 PTY.spawn을 사용하십시오 (물론 자신의 명령으로).
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
그리고 여기에 너무 많은 세부 사항과 함께 긴 대답이 있습니다 .
진짜 문제는 프로세스가 명시 적으로 stdout을 플러시하지 않으면 프로세스가 완료 될 때까지 stdout에 기록 된 모든 내용이 실제로 전송되지 않고 버퍼링되어 IO를 최소화한다는 것입니다 (이것은 분명히 많은 구현 세부 사항입니다. C 라이브러리, 덜 빈번한 IO를 통해 처리량이 최대화되도록 만들어졌습니다. 정기적으로 stdout을 플러시하도록 프로세스를 쉽게 수정할 수 있다면 이것이 해결책이 될 것입니다. 제 경우에는 블렌더 였기 때문에 저와 같은 완전한 멍청한 사람이 소스를 수정하는 것이 약간 위협적이었습니다.
그러나 셸에서 이러한 프로세스를 실행하면 실시간으로 셸에 stdout이 표시되고 stdout이 버퍼링되지 않는 것 같습니다. 내가 믿는 다른 프로세스에서 호출 될 때만 버퍼링되지만 쉘이 처리되는 경우 stdout은 버퍼링되지 않은 실시간으로 표시됩니다.
이 동작은 출력을 실시간으로 수집해야하는 하위 프로세스 인 Ruby 프로세스에서도 관찰 할 수 있습니다. 다음 행을 사용하여 random.rb 스크립트를 작성하십시오.
5.times { |i| sleep( 3*rand ); puts "#{i}" }
그런 다음 루비 스크립트를 호출하여 출력을 반환합니다.
IO.popen( "ruby random.rb") do |random|
random.each { |line| puts line }
end
예상 한대로 실시간으로 결과를 얻지 못했지만 나중에 모두 한꺼번에 얻을 수 있습니다. random.rb를 직접 실행하더라도 STDOUT은 버퍼링되고 있지만 버퍼링되지는 않습니다. 이것은 STDOUT.flush
random.rb의 블록 안에 문 을 추가하여 해결할 수 있습니다 . 그러나 소스를 변경할 수 없으면이 문제를 해결해야합니다. 프로세스 외부에서 플러시 할 수 없습니다.
하위 프로세스가 실시간으로 쉘에 인쇄 할 수 있다면 Ruby로 실시간으로이를 캡처 할 수있는 방법이 있어야합니다. 그리고 있습니다. 내가 믿는 루비 코어 (1.8.6 어쨌든)에 포함 된 PTY 모듈을 사용해야합니다. 슬픈 것은 문서화되지 않았다는 것입니다. 하지만 다행히도 몇 가지 사용 사례를 찾았습니다.
먼저 PTY가 무엇인지 설명하기 위해 의사 터미널을 의미합니다 . 기본적으로 루비 스크립트는 마치 쉘에 명령을 입력 한 실제 사용자 인 것처럼 하위 프로세스에 자신을 표시 할 수 있습니다. 따라서 사용자가 셸을 통해 프로세스를 시작한 경우에만 발생하는 변경된 동작 (예 :이 경우에는 STDOUT이 버퍼링되지 않음)이 발생합니다. 다른 프로세스가이 프로세스를 시작했다는 사실을 숨기면 버퍼링되지 않기 때문에 실시간으로 STDOUT을 수집 할 수 있습니다.
random.rb 스크립트를 자식으로 사용하여이 작업을 수행하려면 다음 코드를 시도하십시오.
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