Ejecute un programa desde Python y haga que continúe ejecutándose después de que se elimine el script.

Resuelto James asked hace 13 años • 6 respuestas

Intenté ejecutar cosas como esta:

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

Esto funciona si el script principal sale correctamente, pero si elimino el script (Ctrl-C), todos mis procesos secundarios también se eliminan. Hay alguna manera de evitar esto?

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

James avatar May 16 '11 04:05 James
Aceptado

El proceso hijo recibe lo mismo SIGINTque su proceso padre porque está en el mismo grupo de procesos. Puede colocar al hijo en su propio grupo de procesos llamando os.setpgrp()al proceso hijo. PopenEl argumento de preexec_fnes útil aquí:

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

( preexec_fnEs solo para un*x-oids. Parece haber un equivalente aproximado para Windows " creationflags=CREATE_NEW_PROCESS_GROUP", pero nunca lo he probado).

JonMc avatar Jun 04 '2013 22:06 JonMc

La forma habitual de hacer esto en sistemas Unix es bifurcar y salir si eres el padre. Mira esto os.fork().

Aquí hay 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)
edoloughlin avatar May 15 '2011 21:05 edoloughlin

Desde 3.2 también puedes usar start_new_sessionflag (solo POSIX).

import subprocess

p = subprocess.Popen(["sleep", "60"], start_new_session=True)
ret = p.wait()

Ver start_new_session en el constructor Popen

Zhiwei Huang avatar Nov 02 '2020 15:11 Zhiwei Huang