如何使用独立的stdout,stderr和stdin派生新进程?

mer*_*011 5 python linux fork 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)
Run Code Online (Sandbox Code Playgroud)

之所以失败,是因为一旦退出父进程,子进程便被杀死。我知道,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)
Run Code Online (Sandbox Code Playgroud)

在这里,子进程不再与父进程一起消亡,但是在父进程去世后,子进程将无法再读取输入和写入输出。

因此,我想知道我是怎么一个新的进程具有完全独立的stdoutstderrstdin。独立意味着父进程可以终止(通常),而子进程(无论是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
Run Code Online (Sandbox Code Playgroud)

上面的代码具有我所寻求的所有行为,但是可以人为地使Python进程保持活动状态。我正在尝试实现这种确切的行为,而没有使Python进程存活

警告:我正在ssh上运行这些应用程序,因此生成新的GUI窗口不是可行的解决方案。

期望的行为

  1. 我运行python代码。
  2. 我得到一个闪亮的新bash外壳,其工作原理与刚开始的bash外壳完全相同。
  3. 文件/tmp/FooBar已创建。
  4. 原始的Python脚本完成了。
  5. 我继续使用闪亮的新bash外壳,并且的输出ps aux | grep python不包含我刚运行的python脚本。

Pie*_*erz 0

您的第一个示例对 Popen() 进行了额外的不必要的调用,因为调用便利函数只会在 shell 中执行其命令并退出,因此如果您只是运行以下命令,它就会起作用:

from subprocess import call, Popen

call("echo Hello > /tmp/FooBar", shell=True)
Run Code Online (Sandbox Code Playgroud)

但是,如果您想向 shell 发送一系列命令,则需要使用附加到管道的 stdin 打开 shell,这样它就不会与父 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()
Run Code Online (Sandbox Code Playgroud)

如果您还想控制输出,则将 stdout 和 stderr 重定向到 PIPE(即) stdout = subprocess.PIPEstderr = subprocess.PIPE然后调用 p.stdout.read() 以根据需要获取输出。

为了允许进程在退出 python 后继续运行,可以&在命令末尾添加运算符,以便它继续在后台运行,例如:

call("nc -l 2000 > /tmp/nc < &",shell=True)
Run Code Online (Sandbox Code Playgroud)

要运行一个进程,以便 stdin 和 stdout 都保持连接,就可以使用 shell 重定向。要保持对标准输入的访问,可以使用以下命令创建命名管道mkfifo

call("mkfifo /tmp/pipe",shell=True)
call("tail -f /tmp/pipe > /tmp/out &",shell=True)
Run Code Online (Sandbox Code Playgroud)

要提供输入标准输入,只需将数据从 shell 发送到管道 .eg :

$ echo 'test' > /tmp/pipe
Run Code Online (Sandbox Code Playgroud)