从Python运行程序,并在脚本被终止后继续运行

48 投票
6 回答
49704 浏览
提问于 2025-04-16 17:41

我试过这样运行:

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

如果父脚本正常退出,这样是可以的。但是如果我强制结束脚本(按Ctrl-C),所有的子进程也会被杀掉。有没有办法避免这种情况呢?

我关心的平台是OS X和Linux,使用的是Python 2.6 Python 2.7。

6 个回答

16

经过一个小时的各种尝试,这个方法对我有效:

process = subprocess.Popen(["someprocess"], creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP)

这是适用于Windows的解决方案。

66

子进程会收到和父进程一样的 SIGINT 信号,因为它们在同一个进程组里。你可以通过在子进程中调用 os.setpgrp() 来把子进程放到自己的进程组里。Popenpreexec_fn 参数在这里很有用:

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

(preexec_fn 只适用于类 Unix 系统。Windows 上似乎有一个类似的选项 "creationflags=CREATE_NEW_PROCESS_GROUP",但我自己没有试过。)

32

在Unix系统上,通常的做法是先复制一个进程,然后如果你是父进程就退出。可以看看 os.fork() 这个函数。

下面是一个可以完成这个任务的函数:

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)

撰写回答