2011-05-15 12 views
27

He intentado correr cosas como esta:Ejecutar un programa de pitón, y hacer que siga funcionando después de que el script se mató

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

Esto funciona si el guión padre sale con gracia, pero si mato a la secuencia de comandos (Ctrl-C), todos los procesos de mi hijo son asesinados también. Hay alguna manera de evitar esto?

Las plataformas que me interesan son OS X y Linux, usando Python 2.6 y Python 2.7.

Respuesta

22

La forma habitual de hacerlo en sistemas Unix es bifurcar y salir si eres el padre. Eche un vistazo al os.fork(). Puede echar un vistazo here para más información.

Aquí es una función que hace el trabajo:

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

Si me bifurco, y luego mato la mitad de la horquilla (en lugar de permitir que salga), ¿eso matará el nuevo proceso? – James

+1

Bien, después de leerlo más a fondo: ¿esto requiere bifurcar dos veces para evitar recibir señales? Me gustaría que el proceso principal siga siendo interactivo; su trabajo es supervisar los procesos que genera, lo que no es posible si tiene que rechazar el shell. – James

+0

¡Gracias! He agregado mi implementación a tu respuesta. – James

-6

Run subprocess.Popen() en un hilo separado.

+0

Esto no parece funcionar. – James

39

El proceso secundario recibe el mismo SIGINT que su proceso primario porque está en el mismo grupo de procesos. Puede poner al niño en su propio grupo de proceso llamando a os.setpgrp() en el proceso secundario. argumento preexec_fn de Popen es útil aquí:

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

(preexec_fn es para la ONU * solo x-oids Parece que hay un equivalente aproximado para Windows "creationflags = CREATE_NEW_PROCESS_GROUP", pero nunca lo he probado..)

+0

Gracias por su respuesta; ¡esto funciona para mi! Sin embargo, tengo curiosidad por saber por qué mi comando se detiene (proceso muere) después de algún punto, si omito los agrupamientos 'stdout' y' stderr'. – danuker

Cuestiones relacionadas