Techioz Blog

Ruby と IO.popen を使用してプロセスを読み書きする方法は?

概要

Ruby と IO.popen を使用してプロセスを読み書きする方法は?


output = IO.popen("irb", "r+") do |pipe|
  pipe.gets
  pipe.puts "10**6"
  pipe.gets
  pipe.puts "quit"
end

そう書き直します


IO.popen("irb", "w+") do |pipe|
  3.times {puts pipe.gets} # startup noise
  pipe.puts "10**6\n"
  puts pipe.gets # I expect " => 1000000"
  pipe.puts "quit" # I expect exit from irb
end 

解決策

一般に、上記の例は、パイプがまだ書き込みのために開いており、呼び出したコマンド (Ruby インタプリタ) がさらなるコマンド/データを期待しているため、ハングします。

もう 1 つの答えは、END を Ruby に送信します。これはここでは機能しますが、このトリックは、Popen 経由で呼び出す可能性のある他のプログラムでは機能しません。

Popen を使用する場合は、IO#close_write でパイプを閉じる必要があります。

 IO.popen("ruby", "r+") do |pipe|
   pipe.puts "puts 10**6"

   pipe.close_write    # make sure to close stdin for the program you call

   pipe.gets
 end

参照: Ruby 3.1 Popen*

さらに詳細に:

Ruby では、IO.popen、IO.popen2、IO.popen2e、および IO.popen3 はサブプロセスを操作するために使用されるメソッドであり、入力、出力、エラー ストリームの処理方法が異なります。ここでは、違いとそれぞれをいつ使用するかについて説明します。

各バージョンをいつ使用するかは、特定の要件によって異なります。