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

时间:2011-05-15 21:03:31

标签: python subprocess nohup

我尝试过这样的事情:

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。

5 个答案:

答案 0 :(得分:46)

子进程接收与父进程相同的SIGINT,因为它位于同一进程组中。您可以通过在子进程中调用os.setpgrp()将子进程放入其自己的进程组中。 Popen的preexec_fn参数在这里很有用:

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

(preexec_fn仅用于un * x-oids。似乎有一个粗略的等效Windows“creationflags = CREATE_NEW_PROCESS_GROUP”,但我从未尝试过。)

答案 1 :(得分:25)

在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)

答案 2 :(得分:2)

经过一个小时的尝试,这对我有用:

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

这是Windows的解决方案。

答案 3 :(得分:0)

with open('/dev/null', 'w') as stdout, open('logfile.log', 'a') as stderr:
    subprocess.Popen(['my', 'command'], stdout=stdout, stderr=stderr)

类子流程。Popen(...)

在新进程中执行子程序。 在POSIX上,该类使用类似于os.execvp()的行为来执行 子程序。在Windows上,该类使用Windows CreateProcess() 功能。

os.execvpe(file,args,env)

这些功能全部执行一个新程序,替换当前程序 处理;他们不回来。在Unix上,新的可执行文件已加载 进入当前进程,并具有与 呼叫者。错误将被报告为OSError异常。

答案 4 :(得分:0)

从3.2开始,您还可以使用start_new_session标志(仅适用于POSIX)。

import subprocess

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

请参见start_new_session in Popen constructor