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

Jam*_*mes 37 python subprocess nohup

我试过这样的事情:

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

如果父脚本正常退出,则此方法有效,但如果我终止脚本(Ctrl-C),则所有子进程也将被终止.有办法避免这种情况吗?

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

小智 52

子进程接收与父进程相同的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
                 )
Run Code Online (Sandbox Code Playgroud)

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

  • 如果调用“setpgrp”,是否需要“nohup”?后者是否会阻止子进程从父进程获取“SIGHUP”,因为它不再属于同一进程组? (2认同)

edo*_*lin 27

在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)
Run Code Online (Sandbox Code Playgroud)


Dan*_*nov 16

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

process = subprocess.Popen(["someprocess"], creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP)
Run Code Online (Sandbox Code Playgroud)

这是 Windows 的解决方案。