带有shell = True的python子进程:重定向和与平台无关的子进程终止

时间:2010-10-11 16:23:46

标签: python shell logging subprocess redirect

我很难从python子进程模块中得到我想要的东西(它应该是一个统一的/独立于平台的抽象,afaik,但不要让我开始这样做:))。

所以我所追求的简单事情如下。我想

  • 启动外部(stdio)应用程序(可能使用子进程),我使用shell样式重定向(如'./myapp> stdout_log> stderr_log')
    • 基本上我想执行一个shell命令行,所以我必须为subprocess.Popen()指定 shell = True (否则命令行中的重定向将不起作用)< / LI>
  • 我想以异步方式启动此命令行(因此它作为一个独立的子进程运行,但我的python进程不会等待它完成)
  • (我的父python进程会不时查看子进程的日志以提取信息,但这与问题无关)
  • 如果我的父python进程决定,它应该能够终止这个子进程。

现在,我的主要问题是

  • 我基本上被迫使用 shell = True 来重定向工作
  • 在父python进程中处理子节点的stdout / stderr不是一个选项,因为我找不到以非等待方式执行它的功能(并且父python进程必须做孩子跑步的其他事情)
  • 如果我使用 shell = True ,则subprocess.kill()将仅终止shell但不终止子进程
  • 我需要一个可靠的子进程终止方法,可以在任何平台上运行(但至少是linux和windows)

我希望我足够具体。提前感谢任何提示/提示 - 我只花了一整天的子流程,恕我直言<罢工>痛苦远离平台无关或简单:((但也许只是我)

更新(2010-10-13):

如果你启动一个子进程(即使shell = False),那么subprocess.Popen.kill()函数只会杀死那个子进程(所以如果有任何“孙子”进程,它们就不会被终止。)

我读到了使用preexec_fn参数在所有子进程上设置sid,但它只是unix:timeout a subprocess

4 个答案:

答案 0 :(得分:4)

上次我处于类似的情况时,我发现最简单的(实际上也是唯一的)解决办法就是启动一个处理你的子进程的线程。您可以使用此方法采用不同的路由,无论是解析shell样式命令的管道,还是执行python代码(由于阻塞而您认为不是一个选项),这将同时修复您的杀人问题。基本上,线程封装似乎是要走的路。

可悲的是,我对subprocess的体验都在Windows平台上,它有很多自己的小怪癖。 subprocess似乎有很多瑕疵,尽管它应该做得很好,因为它应该替换popenpopen2等模块。

答案 1 :(得分:3)

回答一些问题:

答案 2 :(得分:3)

我最近也遇到过类似的情况,我创建了一个使用shell=True的python子进程,需要稍后将其删除。但是,由于shell参数,“真实”进程是shell的子进程,即主进程的孙子。杀死子shell不会自动杀死孙子。

在我的顶级python脚本中:

childProcess = subprocess.Popen('python other.py', shell=True)

为了杀死shell和'实际工作'的孙子,我做了这个:

subprocess.call("ps -ef | awk '$3 == \"" + str(childProcess.pid) + "\" {print $2}' | xargs kill -9", shell=True)
childProcess.kill()

第一行杀死子进程的所有子进程(基于ps -ef个父进程,第二行终止了该进程。

有趣的是,这在Ubuntu上是必要的,但在Mac OSX上并不是绝对必要的,因为在Mac上,孙子似乎接管了原来的子shell进程ID。

答案 3 :(得分:2)

一次解决一个问题:

  

我基本上被迫使用shell = True来重定向工作

您不能只使用stdoutstderr参数吗?

out_log = open("stdout_log", "w")
err_log = open("stderr_log", "w")
subproc = subprocess.popen(..., stdout=out_log, stderr=err_log, ...)
  

在父python进程中处理子进程的stdout / stderr不是一个选项,因为我找不到以非等待方式执行它的功能(并且父进程必须在子进程运行时执行其他操作)

这是因为Windows。在Unix类型的操作系统上,您只需使用select模块。 Windows在套接字上只能select,而不是文件。

  

如果我使用shell = True,那么subprocess.kill()将只终止shell但不终止子进程

因为shell=True shell 子进程,并且命令是其子进程。

  

我需要一个可靠的子进程终止方法,适用于任何平台(但至少Linux和Windows)

Windows是否存在可靠的子进程终止方法?最后我听说,即使任务管理器的结束任务也不是100%可靠。在Linux中,您可能无法杀死通过崩溃的驱动程序打开文件的进程。

像Stigma所说,对于Windows支持,您需要使用线程作为子进程代理。此外,您应该尝试使用shell=False,如果不能,请详细说明原因。