他のプログラムと対話できる python プログラムを作成しようとしています。これは、stdin を送信し、stdout データを受信することを意味します。pexpect を使用することはできません (ただし、デザインの一部に影響を与えたことは間違いありません)。私が現在使用しているプロセスは次のとおりです。
- サブプロセスの stdout に pty をアタッチします
- チェックしてサブプロセスが終了するまでループします
subprocess.poll
- stdout に利用可能なデータがある場合、そのデータを現在の stdout にすぐに書き込みます。
- 終了!
私は動作するいくつかのコード (以下) のプロトタイプを作成していますが、私を悩ませている 1 つの欠陥があるようです。使用時にタイムアウトを指定しないと、子プロセスが完了した後、親プロセスがハングしますselect.select
。タイムアウトを設定したくないのです。少しだけ汚れているようです。ただし、この問題を回避するために私が試みた他のすべての方法は機能していないようです。Pexpect は、 and の代わりに and を使用して、私が好まないソリューションを使用することで回避してos.execv
いるpty.fork
ようsubprocess.Popen
ですpty.openpty
。サブプロセスの寿命をチェックする方法に何か問題がありますか? 私のアプローチは間違っていますか?
私が使用しているコードは以下のとおりです。私はこれを Mac OS X 10.6.8 で使用していますが、Ubuntu 12.04 でも動作させる必要があります。
これはサブプロセスランナーrunner.py
です:
import subprocess
import select
import pty
import os
import sys
def main():
master, slave = pty.openpty()
process = subprocess.Popen(['python', 'outputter.py'],
stdin=subprocess.PIPE,
stdout=slave, stderr=slave, close_fds=True)
while process.poll() is None:
# Just FYI timeout is the last argument to select.select
rlist, wlist, xlist = select.select([master], [], [])
for f in rlist:
output = os.read(f, 1000) # This is used because it doesn't block
sys.stdout.write(output)
sys.stdout.flush()
print "**ALL COMPLETED**"
if __name__ == '__main__':
main()
これはサブプロセス コードoutputter.py
です。奇妙なランダム部分は、ランダムな間隔でデータを出力するプログラムをシミュレートするためのものです。必要に応じて削除できます。それは問題ではありません:
import time
import sys
import random
def main():
lines = ['hello', 'there', 'what', 'are', 'you', 'doing']
for line in lines:
sys.stdout.write(line + random.choice(['', '\n']))
sys.stdout.flush()
time.sleep(random.choice([1,2,3,4,5])/20.0)
sys.stdout.write("\ndone\n")
sys.stdout.flush()
if __name__ == '__main__':
main()
皆様のご協力に感謝いたします。
追記
stdout がバッファリングされないようにするため、pty が使用されます。