There's an echo in my head

日々のメモ。

PTY.spawnで外部コマンドを実行する

以前Open3.popen3で外部コマンドの出力を随時受け取って表示するということをやったけど、それでは不便な場面が出てきた。

というのも、例えばgrepでマッチした部分を色付けしたものを得ようとしてもOpen3.popen3で受け取ることはできない。これはgrepが出力先がttyのときだけ色付けするようになっているのに対して、Open3.popen3のやりとりにttyが使われていないことが原因らしい。((出力先のIOがttyかどうかはrubyだとIO#tty?で調べられる。))

正直ttyってなんなのかわからないけど、とりあえずPTY.spawnを使うと擬似ttyをruby上に作ったうえで外部コマンドとやりとりできるとのことがわかったのでやってみた。

require "pty"

PTY.spawn("long-long-command") do |r, w, pid|
  # rはコマンドの出力IO。標準出力と標準エラーの両方が同じところから出てくる
  # wはコマンドへの書き込みIO

  w.close_write
  r.sync = true

  begin
    r.each do |line|
    next if line.nil? || line.empty?
    puts line
  rescue Errno::EIO
  ensure
    ::Process.wait pid
  end
end

ちなみにknife-soloでの変更点などの出力の色付けは出力先がttyでないと行われないんだけど、それを裏で叩いているpaknifeではOpen3.popen3を使っているため色付けされない。

なので色付けされた出力を得ようとPTY.spawnを使うようにしてみたんだけど、一部分だけが色づくだけで変更箇所などは色付けされないので、どこが原因かまだ探っているところだ。

参考

このブログに出てくるコードスニペッツは、引用あるいは断りがない限りMITライセンスです。