すごく昔こういう記事を書いたんだけれど。
某フィヨルド方面より、まさかのこの記事に関する質問が来て、さらに「入力を渡すにはどうすればいいか」という追加質問がきたのであった。
試した感じ、なんとも素直に動かなかったので、どうすればいいかを書き残しておこうと思う。
ポイントは2つで、
- ttyの入力を終了させるために、
^D
に相当するEOF
EOT
コードこと"\u{04}"
を送り込む - 入力した行はそのまま
pty_out
から取ろうとするとフィードバックして取得できてしまうので、1行捨てる
これで大体想定した挙動になるはず。ただ、当然stdout/errが混ざるので、標準出力やエラー出力のテストなら Open3.capture3
などが適切だと思う。
サンプルコード
require 'pty' status = nil PTY.spawn("tac") do |pty_out, pty_in, pid| 3.times do |i| # 書いたら捨てる pty_in.write "Hola" * (i+1) + "\n" pty_out.gets end # ^D 相当の制御文字 pty_in.puts "\u{04}" pty_out.gets while !(status ||= PTY.check(pid)) && l = pty_out.gets puts "PTY(out): #{l}" end # MacOS では上のチェックでstatusが埋まる前に、 # pty_out.gets でnilを返してループを抜けるので改めて取得する until status ||= PTY.check(pid) end end p status
結果
$ ruby pty.rb PTY(out): HolaHolaHola PTY(out): HolaHola PTY(out): Hola #<Process::Status: pid 2217 exit 0>