pexpect において、標準出力にログを出力させながら、端末の出力に関係なくコマンドを実行させたいとき

この記事を作った動機 Onenote代替品の作成の研究の一環で、pexpect を使って端末のセッションを維持させながらとにかくコマンドを実行させたいということがあり、その過程で試行錯誤があったため記録したい。 現状使っているもの 以下は現状使っている実装の参考例である。一定時間置いた後に、1000文字(出力に対して、十分大きい数字を設定する)ずつターミナルを読み出している。作ったセッション内のターミナルに何が出力されるかわからないが、とにかくコマンドを実行させて、その結果を出力することに以下のスクリプトは特化している。 待ち時間は適宜調整する必要がある。 スクリプト本体 (新しい 2026/9/21 時点) import pexpect,time,sys session = pexpect.spawn("/bin/bash",timeout=5, encoding='utf-8') session.logfile_read = sys.stdout session.sendline("ls") time.sleep(1) session.flush() session.read_nonblocking(1000,timeout=None) session.sendline("gcc") time.sleep(1) session.flush() session.read_nonblocking(1000,timeout=None) スクリプト本体 (古い) 一定時間置いたあとに、何でもマッチングするexpectを配置しているのは、標準出力であるstdoutに対して、コマンドの実行結果を吐き出させたいためである。 import pexpect,time,sys session = pexpect.spawn("/bin/bash",timeout=5, encoding='utf-8') session.logfile_read = sys.stdout session.sendline("ls") time.sleep(1) session.expect(".+") session.sendline("gcc") time.sleep(1) session.expect(".+") 実行結果 python main1.py ls # ⠀aaaa ⠀main.py ⠀main1.py ⠀readme.md ⠀test/ gcc # gcc: fatal error: 入力ファイルがありません # compilation terminated. 追記 (2026/9/16) このやり方は非常に簡易的にしか動作せず、副作用があることが分かった。具体的には".+“でexpectさせるとログが出てくるのは、pexpectが期待した文字列を待機している状態になるからであることが分かった。つまるところ、タイムアウトに引っかかると例外を出して強制終了してしまう。 それを防ぐには、pexpectにおいては、waitという専用の関数があるため、それを利用することができることが分かった。ただこれだとログが出てこない(”.*“と同じ挙動になる)ため、なにかさらに工夫が必要そうなことが分かっている。 また、pexpect にて同じ端末に出力を出させると端末の表示がぐちゃぐちゃになってしまう。最近考えていることとして個別にファイルとしてlogをテキストファイルとして書き出させてそれをwatch -n 0.1 "cat log | tail -n 10"みたいにすればよいのではないかと思い始めている。 ...

2026年9月9日