2011-05-15 10 views
27

Ho provato a fare funzionare le cose in questo modo:Eseguire un programma in pitone, e lo hanno continuano a funzionare dopo lo script viene ucciso

subprocess.Popen(['nohup', 'my_command'], 
       stdout=open('/dev/null', 'w'), 
       stderr=open('logfile.log', 'a')) 

Questo funziona se lo script genitore esce con grazia, ma se uccido la script (Ctrl-C), anche tutti i miei processi figli vengono uccisi. c'è un modo per evitarlo?

Le piattaforme a cui tengo sono OS X e Linux, utilizzando Python 2.6 e Python 2.7.

risposta

22

Il modo usuale per eseguire questa operazione sui sistemi Unix è forchetta e uscita se si è genitori. Dai un'occhiata a os.fork(). Potresti dare un'occhiata a here per ulteriori informazioni.

Ecco una funzione che fa il lavoro:

def spawnDaemon(func): 
    # do the UNIX double-fork magic, see Stevens' "Advanced 
    # Programming in the UNIX Environment" for details (ISBN 0201563177) 
    try: 
     pid = os.fork() 
     if pid > 0: 
      # parent process, return and keep running 
      return 
    except OSError, e: 
     print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror) 
     sys.exit(1) 

    os.setsid() 

    # do second fork 
    try: 
     pid = os.fork() 
     if pid > 0: 
      # exit from second parent 
      sys.exit(0) 
    except OSError, e: 
     print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror) 
     sys.exit(1) 

    # do stuff 
    func() 

    # all done 
    os._exit(os.EX_OK) 
+0

Se forzo, e poi uccido metà della forchetta (piuttosto che lasciarlo uscire), ucciderà il nuovo processo? – James

+1

Ok, dopo ulteriori letture: questo richiede due volte una biforcazione per evitare di ricevere i segnali? Mi piacerebbe che il processo genitore rimanesse interattivo --- il suo compito è monitorare i processi che genera - il che non è possibile se deve rinnegare la shell. – James

+0

Grazie! Ho aggiunto la mia implementazione alla tua risposta. – James

-6

Run subprocess.Popen() in un thread separato.

+0

Questo non sembra funzionare. – James

39

Il processo figlio riceve lo stesso SIGINT del processo padre perché si trova nello stesso gruppo di processi. Puoi mettere il bambino nel proprio gruppo di processi chiamando os.setpgrp() nel processo figlio. argomento preexec_fn di Popen è utile qui:

subprocess.Popen(['nohup', 'my_command'], 
       stdout=open('/dev/null', 'w'), 
       stderr=open('logfile.log', 'a'), 
       preexec_fn=os.setpgrp 
       ) 

(preexec_fn è solo un * x-OID Sembra che ci sia un equivalente di massima per Windows "creationflags = CREATE_NEW_PROCESS_GROUP", ma non ho mai provato..)

+0

Grazie per la risposta; per me funziona! Tuttavia, sono curioso di sapere perché il mio comando si arresta (processo muore) dopo un certo punto, se ometto gli algoritmi 'stdout' e' stderr'. – danuker

Problemi correlati