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

发布于 2024-09-27 03:48:21 字数 1177 浏览 1 评论 0原文

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

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

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

现在,我的主要问题是

  • 我基本上被迫使用 shell=True,以获得重定向工作
  • 在父 python 进程中处理子进程的 stdout/stderr 不是一个选项,因为我不能'找不到以非等待方式执行此操作的功能(并且父 python 进程必须在子进程运行时执行其他操作)
  • 如果我使用 shell=True 则子进程.kill() 只会终止 shell,但不会终止子进程
  • 我需要一个可靠的子进程终止方法,可以在任何平台上工作(但至少是 Linux 和 Windows)

我希望我足够具体。感谢您提前提供任何提示/提示——我刚刚花了一整天的时间来处理子流程,恕我直言,它远非平台独立或简单:(但也许只是我一个人)

更新( 2010-10-13):

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

我读到了有关使用 preexec_fn 参数在所有子进程上设置 sid 的内容,但它仅限于 UNIX: 使子进程超时

I'm having a hard time getting what I want out of the python subprocess module (which supposed to an unified/platform-independent abstraction, afaik, but don't get me started on that :)).

So the simple thing what I'm after is the following. I want to

  • Launch an external (stdio) application (possibly with subprocess), where I use shell-style redirections (like './myapp >stdout_log >stderr_log')
    • Basically i want to execute a shell command-line, so I have to specify shell=True for subprocess.Popen() (or else redirections in the command-line won't work)
  • I want to launch this command line in an async fashion (so it runs as an independent sub-process, but my python process won't wait for it's completion)
  • (My parent python process would look at the child process's logs from time to time to extract information, but this is irrelevant to the question)
  • If my parent python process decides, it should be able to terminate this child process.

Now, my main problems are that

  • I'm basically forced to use shell=True, to get redirections to work
  • Processing the child's stdout/stderr in the parent python process is not an option, since I couldn't find functionality for doing it in a non-waiting way (and the parent python process must do other things while the child is running)
  • If I use shell=True then subprocess.kill() will only terminate the shell but not the child process
  • I'd need a reliable child process termination method that works on any platform (but at least linux and windows)

I hope I was specific enough. Thanks for any tips/hints in advance -- I just spent a whole day with subprocess, and IMHO it's a pain far from either platform-independent or simple :( (but perhaps it's just me)

UPDATE (2010-10-13):

If you launch a sub-process (even with shell=False), then the subprocess.Popen.kill() function will only kill that sub-process (so if there are any "grandchild" processes, they won't be terminated.)

I read about using the preexec_fn parameter to set the sid on all child processes, but it's unix-only: timeout a subprocess

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

沙沙粒小 2024-10-04 03:48:22

一次解决一个问题:

我基本上被迫使用 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 不是一个选项,因为我找不到以非等待方式执行此操作的功能(并且父 python 进程必须在子进程运行时执行其他操作) )

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

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

因为当 shell=True 时,shell 子进程,并且命令是它的子项。

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

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

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

Going through your problems one at a time:

I'm basically forced to use shell=True, to get redirections to work

You can't just use the stdout and stderr parameters?

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

Processing the child's stdout/stderr in the parent python process is not an option, since I couldn't find functionality for doing it in a non-waiting way (and the parent python process must do other things while the child is running)

This is because of Windows. On Unix-type OSes, you just use the select module. Windows can only select on sockets, not files.

If I use shell=True then subprocess.kill() will only terminate the shell but not the child process

Because when shell=True the shell is the child process, and the commands are its children.

I'd need a reliable child process termination method that works on any platform (but at least linux and windows)

Does a reliable child process termination method even exist for Windows? Last I heard, even Task Manager's End Task wasn't 100% reliable. And in Linux, you might not be able to kill a process that has a file open via a crashed driver.

Like Stigma said, for Windows support you will need to use threads as subprocess proxies. Also, you should try to run with shell=False, and if you can't, please elaborate as to why not.

北恋 2024-10-04 03:48:21

上次我遇到类似的情况时,我发现最简单(实际上是唯一)的解决方案是启动一个负责子进程的线程。您可以使用此方法采取不同的路线,无论是解析 shell 样式命令的管道并在 python 代码中执行这些命令(您所说的由于阻塞而不是一个选项),这将同时修复您的问题杀人问题。基本上,线程封装似乎是可行的方法。

遗憾的是,我对 subprocess 的体验都是在 Windows 平台上进行的,该平台有很多自己的小怪癖。 subprocess 似乎有很多缺陷,尽管考虑到 popenpopen2 等的存在,它必须做得还不错。其应该替换的模块。

Last time I was in a similar situation, I found out the easiest (and practically the only) solution was to kick off a thread which takes care of your child process. You can take different routes with this method, be it to parse the piping of the shell-style command and perform those in python code (which you said wasn't an option due to the blocking), which would at the same time fix your killing problem. Basically, thread encapsulation seems like the way to go.

Sadly my experience with subprocess is all on the Windows platform, which has tons of its own little quirks. subprocess has a lot of flaws all-around it seems, although it must do an okay job given the existence of the popen, popen2 and so forth modules that it is supposed to replace.

花开柳相依 2024-10-04 03:48:21

我最近也遇到了类似的情况,我创建了一个使用 shell=True 的 python 子进程,稍后需要将其杀死。然而,由于 shell 参数,“真实”进程是 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。

I too had a similar situation recently, I created a python subprocess that uses shell=True, and needed to kill it later. However, because of the shell param, the 'real' process is a child of the shell, i.e. a grandchild of the main process. Killing the child shell does not automatically kill off the grandchild.

In my top-level python script:

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

To kill the shell and the 'real work' grandchild, I did this:

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

The first line kills off all children of the child process (based on ps -ef parentage, the second line kills off the child.

Interestingly, this is necessary on Ubuntu, but not strictly necessary on Mac OSX, as on the Mac the grandchild seems to take over the original child shell process id.

秋凉 2024-10-04 03:48:21

回答一些问题:

Answering some of the issues:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文