ruby-talk の話見ててちょっと思いだしたんですが.... 1.7.x のどこかから PTY.spawn は子プロセスの監視にスレッドを使うように なりました. IO#expect は IO.select を使ってタイムアウト付きの expect を実装してい ます. スレッドを使うと select() がスレッドのスケジューリングと干渉して,使え る fd がなくても帰ってきてしまう場合があります. # これは ruby-talk ですでに報告されていて,patch がとりこまれています # が完全な fix はまだだったはず? ....総合すると,「何も考えずに pty の読みだしの方を expect にかけると IO.select が途中で返ってきて,getc が nil を返すから nil.chr が実行さ れ NoMethodError で落ちます」. さらに pty.spawn のブロックは「子スレッドの方で実行される」ので例外か ら recover しようとしたらブロック内で rescue する必要があります.また clearerr() を呼ぶために rescue close で.... 何がいるんでしたっけ? で,実は expect.rb を require して IO.expect を使うより,IO#sysread を 使って EOFError を rescue しておいた方が簡単かもしれません. たとえば今使ってるコードだと ssh を spawn してプロンプトが返ってくるの を待つのに require "pty" $port = 12345 # local port begin PTY.spawn("ssh -L #{$port}:remote:110 remote") do |rf, wf| res = "" begin res << rf.sysread(128).to_s until res =~ /\$/ rescue EOFError sleep 0.5 retry end # some useful stuff. end rescue PTY::ChildExited # ignore. end なんていうことをしています. # 省略したところはまあ,想像の付くとおり :-) 実はもうちょっとましなや # り方は無いものかとも思ってますが. Just FYI. # 実のところ見てる範囲でこんなんで引っかかってる人はいないんで,実はわ # ざわざいうほどのものでもないという可能性もあり? -- 柳川和久 @ 東大阪市 . 大阪府 January 14, 2002 「うむ,奥が深い」「....底は浅いけどね」