サブプロセスにまったく新しい pty を提供する必要がない場合は、プログラムをこれに切り詰めることができると思います。
from argparse import ArgumentParser
import os
import signal
import subprocess
import itertools
# your argumentparser stuff goes here
def become_tty_fg():
os.setpgrp()
hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN)
tty = os.open('/dev/tty', os.O_RDWR)
os.tcsetpgrp(tty, os.getpgrp())
signal.signal(signal.SIGTTOU, hdlr)
if __name__ == "__main__":
args = parser.parse_args()
if args.verbose: print "command is %s" % (args.command)
if args.invert and args.limit==None:
sys.exit("You must define a limit if you have inverted the return code test")
for run_count in itertools.count():
return_code = subprocess.call(args.command, close_fds=True,
preexec_fn=become_tty_fg)
if args.test == True: break
if run_count >= args.limit: break
if args.invert and return_code != 0: break
elif not args.invert and return_code == 0: break
print "Ran command %d times" % (run_count)
このsetpgrp()
呼び出しは、同じセッションで新しいプロセス グループを作成するため、新しいプロセスはユーザーから ctrl-c/ctrl-z/etc を受け取りますが、再試行スクリプトは受け取りません。次に、tcsetpgrp()
新しいプロセス グループを制御 tty のフォアグラウンド グループにします。新しいプロセスは、SIGTTOU
それが発生したときに を取得し ( 以来、setpgrp()
バックグラウンド プロセス グループにあったため)、通常はプロセスを停止させるため、 を無視するのはそのためですSIGTTOU
。サブプロセスが予期しないシグナルテーブルによって混乱する可能性を最小限に抑えるために、SIGTTOU
ハンドラーを以前の状態に戻します。
サブプロセスは tty のフォアグラウンド グループにあるため、その tcgetpgrp() と getpgrp() は同じになり、isatty(1) は true になります (retry.py から継承する stdout が実際には tty であると仮定します)。サブプロセスと tty の間でトラフィックをプロキシする必要はありません。これにより、すべてのselect
イベント処理と fcntl-nonblocking-setting を破棄できます。