2013-03-04 12 views
6

retry.pyという名前のコマンドが失敗した場合、繰り返しコマンド用の単純なラッパースクリプトを作成しました。しかし、私は子コマンドの出力を見たいので、私はいくつかのptyトリックを引き出す必要がありました。これはrsyncのようなプログラムではうまくいきますが、scpのようなプログラムでは、プログレスメーターのようなものを表示するために追加のテストを適用します。私はラッパースクリプトかかわらず実行すると失敗する私はptyの下で実行しているプロセスのターミナルフォアグラウンドプロセスグループをどのように設定しますか?

getpgrp() == tcgetpgrp(STDOUT_FILENO); 

SCPコードが広くあるテストを持っています。

./tty_tests 
isatty reports 1 
pgrps are 13619 and 13619 

と::私はとtcsetpgrpを(使用して試した

./retry.py -v -- ./tty_tests 
command is ['./tty_tests'] 
isatty reports 1 
pgrps are 13614 and -1 
child finished: rc = 0 
Ran command 1 times 

)PTY fdの年代が、その上IOCTLとして終わるあなたは私の簡単なtty_test.cのテストケースと見ることができるようにptysの結果は-EINVALになります。可能であれば、私はPythonのサブプロセス機械を使い続けたいと思っています。あるいは、手動fork/execve'ingが必要です。

答えて

9

私はあなたがサブプロセスに全く新しい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のすべてを行うことができます。

+0

私は試してみましたが、何の効果もありません: > retry.py -v - 〜/ mysrc/retry.git/tty_tests コマンドは['/home/ajb/mysrc/retry.git/tty_tests '] isattyレポート1 pgrpsは28268と-1です。 子が終了しました:rc = 0 Ranコマンド1回 – stsquad

+0

完全なコードを貼り付けることができますか? –

+0

OH!私はちょうどあなたの質問でretry.pyへのリンクを与えたことに気づいた。私は、それが役に立つと思って、ホスト名のように見えるものからリンクを作ることを試みるだけのstackoverflowだと思っていました。私は見てみましょう。 –

関連する問題