我已经阅读了大部分关于subprocess和os.fork()的相关问题,包括关于双重分叉技巧的所有讨论。但是,这些解决方案似乎都不适合我的方案。
我想分叉一个新进程并允许父进程终止(通常)而不会搞砸孩子的stdin,stdout和stderr而不会杀死孩子。
我的第一次尝试是使用subprocess.Popen()
。
#!/usr/bin/python
from subprocess import call,Popen
Popen("/bin/bash", shell=True)
call("echo Hello > /tmp/FooBar", shell=True)
这会失败,因为父进程退出时会导致子进程被终止。我知道creationflags
但这是特定于Windows的,我在Linux上运行。请注意,如果我们通过在其末尾添加无限循环来简单地保持父进程处于活动状态,则上述代码可以很好地工作。这是不可取的,因为父母已经完成了它的工作,并没有真正的理由让它坚持下去。
第二次尝试是使用os.fork()
。
#!/usr/bin/python
from subprocess import call
from os import fork
try:
pid = fork()
if pid > 0:
pass
else: # child process will start interactive process
call("/bin/bash", shell=True)
except:
print "Forking failed!"
call("echo Hello > /tmp/FooBar", shell=True)
这里,子进程不再与父进程一起死亡,但在父进程死后,子进程无法再读取输入和写入输出。
因此,我想知道如何使用完全独立的stdout
,stderr
和stdin
来分叉新流程。独立意味着父进程可以终止(通常),并且子进程(无论是bash还是tmux还是任何其他交互程序)的行为就像父程序没有终止一样。更准确地说,请考虑原始程序的以下变体。
#!/usr/bin/python
from subprocess import call,Popen
Popen("/bin/bash", shell=True)
call("echo Hello > /tmp/FooBar", shell=True)
while True:
pass
上面的代码具有我所寻求的所有行为,但它使Python过程保持人为的活动。我试图实现这个确切的行为,没有Python进程活着。
警告:我正在通过ssh运行这些应用程序,因此产生新的GUI窗口不是一个可行的解决方案。
所需行为:
bash
shell,其工作方式与我开始使用的bash shell完全相同。/tmp/FooBar
。ps aux | grep python
的输出不包含我刚刚运行的python脚本。答案 0 :(得分:0)
你的第一个例子对Popen()有一个额外的不必要的调用,因为call便利函数只会在shell中执行它的命令并退出,所以如果你刚刚运行它会起作用:
from subprocess import call, Popen
call("echo Hello > /tmp/FooBar", shell=True)
但是如果你想将一系列命令发送到shell,那么shell需要打开,stdin连接到管道,这样它就不会与父stdin混在一起(这实际上是你要求的)获得独立标准的条款):
p = Popen("/bin/bash", shell=True, stdin = subprocess.PIPE)
p.stdin.write("echo Hello > /tmp/FooBar\n")
p.stdin.write("date >> /tmp/FooBar\n")
p.terminate()
如果你还要控制输出,那么你将stdout和stderr重定向到PIPE(即stdout = subprocess.PIPE
,stderr = subprocess.PIPE
),然后调用p.stdout.read()以获得所需的输出。 / p>
要允许进程在退出python后继续运行,可以在命令末尾添加&
运算符,以便它继续在后台运行,例如:
call("nc -l 2000 > /tmp/nc < &",shell=True)
要让进程运行,以便stdin和stdout以及仍然连接的进程可以使用shell重定向。要保持对stdin的访问,可以使用mkfifo
创建命名管道,例如:
call("mkfifo /tmp/pipe",shell=True)
call("tail -f /tmp/pipe > /tmp/out &",shell=True)
要提供输入stdin,只需将数据发送到管道即.e.g。来自shell:
$ echo 'test' > /tmp/pipe
答案 1 :(得分:0)
我最近遇到了这个问题,我找到了可能会有所帮助的解决方案,
使用creationflags
告诉Popen,子进程不应继承父进程控制台,因此拥有自己的stdout,stdin和stderr,就好像它是父进程一样。
subprocess.Popen("/bin/bash", creationflags= subprocess.CREATE_NEW_CONSOLE)
Popen根据文档支持creationflags
关键字参数:
creationflags(如果提供)可以是以下一个或多个标志:
CREATE_NEW_CONSOLE
CREATE_NEW_PROCESS_GROUP
ABOVE_NORMAL_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS
HIGH_PRIORITY_CLASS
IDLE_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
REALTIME_PRIORITY_CLASS
CREATE_NO_WINDOW
DETACHED_PROCESS
CREATE_DEFAULT_ERROR_MODE
CREATE_BREAKAWAY_FROM_JOB
您感兴趣的是DETACHED_PROCESS
和CREATE_NEW_CONSOLE
,我用过CREATE_NEW_CONSOLE
,它的工作是产生一个新的过程,就像它是父进程一样,我使用了Python3.5 Windows,在Python 3.7中添加了DETACHED_PROCESS
,并记录了它与CREATE_NEW_CONSOLE
相同。