2013-03-04 6 views
6

मैंने आदेशों को दोहराने के लिए एक सरल रैपर स्क्रिप्ट लिखी है जब वे retry.py कहलाते हैं। हालांकि, जैसा कि मैं बाल कमांड के आउटपुट को देखना चाहता हूं, मुझे कुछ पीटीआई चाल खींचनी पड़ी है। यह rsync जैसे प्रोग्रामों के लिए ठीक काम करता है लेकिन एसपीपी जैसे अन्य लोग अपने प्रगति मीटर जैसी चीजों को दिखाने के लिए अतिरिक्त परीक्षण लागू करते हैं।मैं एक पीटीआई के तहत चल रहे एक प्रक्रिया के लिए टर्मिनल अग्रभूमि प्रक्रिया समूह कैसे सेट करूं?

getpgrp() == tcgetpgrp(STDOUT_FILENO); 

कौन सा विफल रहता है जब मैं हालांकि आवरण स्क्रिप्ट चलाने:

SCP कोड एक परीक्षण मोटे तौर पर यह है कि है।

./tty_tests 
isatty reports 1 
pgrps are 13619 and 13619 

और:

./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 

मैं tcsetpgrp (का उपयोग कर की कोशिश की है), जो प्राइवेट fd की लेकिन उस पर एक IOCTL के रूप में समाप्त होता है तुम मेरे सरल tty_test.c परीक्षण मामले के साथ देख सकते हैं ptys के लिए एक -EINVAL में परिणाम। यदि संभव हो तो मैं पाइथन उपप्रोसेसर मशीनरी का उपयोग करना जारी रखूंगा या इसके लिए मैन्युअल रूप से फोर्क/निष्पादित करने की आवश्यकता होगी?

उत्तर

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() नए प्रक्रिया समूह को नियंत्रण टीटी पर अग्रभूमि बना देता है। नई प्रक्रिया SIGTTOU हो जाती है जब ऐसा होता है (क्योंकि setpgrp() के बाद से, यह पृष्ठभूमि प्रक्रिया समूह में रहा है), जो आमतौर पर प्रक्रिया को रोक देगा, इसलिए SIGTTOU को अनदेखा करने का यही कारण है। हमने SIGTTOU हैंडलर को जो कुछ भी पहले किया था, उसे अप्रत्याशित सिग्नल टेबल द्वारा भ्रमित किए जाने वाले उपप्रोसेस के मौके को कम करने के लिए सेट किया था।

चूंकि सबप्रोसेस अब टीटीई के लिए अग्रभूमि समूह में है, इसलिए यह tcgetpgrp() और getpgrp() समान होगा, और isatty (1) सच होगा (मान लें कि यह redout वास्तव में retry.py से विरासत में है एक टीटीआई)। आपको उपप्रोसेस और टीटीआई के बीच यातायात को प्रॉक्सी करने की आवश्यकता नहीं है, जो आपको सभी select ईवेंट हैंडलिंग और fcntl-nonblocking-सेटिंग को मिटाने देता है।

+0

मैंने इसे आज़माया और इसका कोई प्रभाव नहीं पड़ा: > retry.py -v - ~/mysrc/retry.git/tty_tests कमांड ['/home/ajb/mysrc/retry.git है/tty_tests '] isatty रिपोर्ट 1 pgrps 28268 और -1 बच्चे समाप्त हो गया: आरसी = 0 रण आदेश 1 बार – stsquad

+0

क्या आप कुछ पूरा कोड पेस्ट कर सकते हैं? –

+0

ओएच! मैंने अभी देखा है कि आपने अपने प्रश्न में retry.py का एक लिंक दिया है। मैंने सोचा था कि केवल स्टैकओवरफ्लो सहायक होने की कोशिश कर रहा था और मेजबाननाम की तरह दिखने वाले किसी चीज़ से लिंक बना रहा था। मैं एक नजर मार लूगां। –

संबंधित मुद्दे