9

以下のような関数があるとしましょう。Process.spawn呼び出しの出力をキャプチャするにはどうすればよいですか?また、指定されたタイムアウトよりも時間がかかる場合は、プロセスを強制終了できるはずです。

関数もクロスプラットフォーム(Windows / Linux)である必要があることに注意してください。

def execute_with_timeout!(command)
  begin
    pid = Process.spawn(command)     # How do I capture output of this process?
    status = Timeout::timeout(5) {
      Process.wait(pid)
    }
  rescue Timeout::Error
    Process.kill('KILL', pid)
  end
end

ありがとう。

4

2 に答える 2

12

外部gemを必要とせずに、リダイレクトされた出力を使用して使用するIO.pipeように指示できます。Process.spawn

もちろん、Ruby 1.9.2からのみ開始します(個人的には1.9.3をお勧めします)

以下は、出力とエラー出力の両方をキャプチャするためにSpinachBDDによって内部的に使用される単純な実装です。

# stdout, stderr pipes
rout, wout = IO.pipe
rerr, werr = IO.pipe

pid = Process.spawn(command, :out => wout, :err => werr)
_, status = Process.wait2(pid)

# close write ends so we could read them
wout.close
werr.close

@stdout = rout.readlines.join("\n")
@stderr = rerr.readlines.join("\n")

# dispose the read ends of the pipes
rout.close
rerr.close

@last_exit_status = status.exitstatus

元のソースはfeatures/support/filesystem.rbにあります

Ruby独自のProcess.spawnドキュメントを読むことを強くお勧めします。

お役に立てれば。

PS:私はあなたのために宿題としてタイムアウトの実装を残しました;-)

于 2012-08-30T17:36:27.087 に答える
3

私は Anselm の Ruby フォーラムへの投稿でのアドバイスに従いまし

関数は次のようになります-

def execute_with_timeout!(command)
  begin
    pipe = IO.popen(command, 'r')
  rescue Exception => e
    raise "Execution of command #{command} unsuccessful"
  end

  output = ""
  begin
    status = Timeout::timeout(timeout) {
      Process.waitpid2(pipe.pid)
      output = pipe.gets(nil)
    }
  rescue Timeout::Error
    Process.kill('KILL', pipe.pid)
  end
  pipe.close
  output
end

これでうまくいきますが、この機能をラップするサードパーティの gem を使用したいと思います。これを行うためのより良い方法はありますか?Terminatorを試してみましたが、まさに私が望んでいることを実行しますが、Windows では動作しないようです。

于 2012-08-30T05:28:51.433 に答える