Python 的 Popen 清理

发布于 2024-08-28 09:30:45 字数 476 浏览 8 评论 0原文

我想使用相当于在 perl 中管道传输一些 shell 命令的 python。类似于 python 版本的 open(PIPE, "command |")。

我转到 subprocess 模块并尝试这个:

p = subprocess.Popen("zgrep thingiwant largefile", shell=True, stdout=subprocess.PIPE)

这可以像在 perl 中一样读取输出,但它不会自行清理。当我退出解释器时,我会

grep: writing output: Broken pipe

在 stderr 上吐出几百万次。我想我天真地希望这一切都会为我解决,但事实并非如此。在 p 上调用终止或终止似乎没有帮助。查看进程表,我发现这会杀死 /bin/sh 进程,但将子 gzip 留在原处以抱怨管道损坏。

这样做的正确方法是什么?

I wanted to use a python equivalent to piping some shell commands in perl. Something like the python version of open(PIPE, "command |").

I go to the subprocess module and try this:

p = subprocess.Popen("zgrep thingiwant largefile", shell=True, stdout=subprocess.PIPE)

This works for reading the output the same way I would in perl, but it doesn't clean itself up. When I exit the interpreter, I get

grep: writing output: Broken pipe

spewed all over stderr a few million times. I guess I had naively hoped all this would be taken care of for me, but that's not true. Calling terminate or kill on p doesn't seem to help. Look at the process table, I see that this kills the /bin/sh process, but leaves the child gzip in place to complain about the broken pipe.

What's the right way to do this?

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

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

发布评论

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

评论(4

深空失忆 2024-09-04 09:30:45

问题是管道已满。子进程停止,等待管道清空,但随后进程(Python 解释器)退出,破坏了管道的末尾(因此出现错误消息)。

p.wait() 不会帮助你:

警告如果子进程生成足够的输出到 stdout 或 stderr 管道,从而阻塞等待操作系统管道缓冲区接受更多数据,这将导致死锁。使用 communicate() 来避免这种情况。

http://docs.python.org/library/subprocess。 html#subprocess.Popen.wait

p.communicate() 不会帮助你:

注意读取的数据会缓存在内存中,因此如果数据量较大或无限制,请勿使用此方法。

http://docs.python.org/library/subprocess。 html#subprocess.Popen.communicate

p.stdout.read(num_bytes) 不会帮助你:

警告使用communicate()而不是.stdin.write.stdout.read.stderr.read 以避免由于任何其他操作系统管道缓冲区填满并阻塞子进程而导致的死锁。

http://docs.python.org/library/subprocess。 html#subprocess.Popen.stdout

这个故事的寓意是,对于大输出,如果您的程序试图读取数据,subprocess.PIPE 注定会失败(在我看来,您应该能够将 p.stdout.read(bytes) 放入 while p.returncode is None: 循环中,但上面的警告表明这可能会死锁)。

文档建议用以下内容替换 shell 管道:

p1 = Popen(["zgrep", "thingiwant", "largefile"], stdout=PIPE)
p2 = Popen(["processreceivingdata"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

请注意,p2 直接从 p1 获取其标准输入。这应该避免死锁,但考虑到上面相互矛盾的警告,谁知道

无论如何,如果最后一部分不适合您(不过,它应该),您可以尝试创建一个临时文件,写入第一次调用的所有数据,然后使用临时文件作为下一个流程的输入。

The issue is that the pipe is full. The subprocess stops, waiting for the pipe to empty out, but then your process (the Python interpreter) quits, breaking its end of the pipe (hence the error message).

p.wait() will not help you:

Warning This will deadlock if the child process generates enough output to a stdout or stderr pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.

http://docs.python.org/library/subprocess.html#subprocess.Popen.wait

p.communicate() will not help you:

Note The data read is buffered in memory, so do not use this method if the data size is large or unlimited.

http://docs.python.org/library/subprocess.html#subprocess.Popen.communicate

p.stdout.read(num_bytes) will not help you:

Warning Use communicate() rather than .stdin.write, .stdout.read or .stderr.read to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process.

http://docs.python.org/library/subprocess.html#subprocess.Popen.stdout

The moral of the story is, for large output, subprocess.PIPE will doom you to certain failure if your program is trying to read the data (it seems to me that you should be able to put p.stdout.read(bytes) into a while p.returncode is None: loop, but the above warning suggests that this could deadlock).

The docs suggest replacing a shell pipe with this:

p1 = Popen(["zgrep", "thingiwant", "largefile"], stdout=PIPE)
p2 = Popen(["processreceivingdata"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

Notice that p2 is taking its standard input directly from p1. This should avoid deadlocks, but given the contradictory warnings above, who knows.

Anyway, if that last part doesn't work for you (it should, though), you could try creating a temporary file, writing all data from the first call to that, and then using the temporary file as input to the next process.

§对你不离不弃 2024-09-04 09:30:45

打开管道后,您可以使用命令输出:p.stdout

for line in p.stdout:
    # do stuff
p.stdout.close()

After you open the pipe, you can work with the command output: p.stdout:

for line in p.stdout:
    # do stuff
p.stdout.close()
栀梦 2024-09-04 09:30:45

你是如何执行这个过程的?

正确的方法是使用

p.communicate()

查看文档了解更多详细信息。

How did you executed this process?

Proper way is to use

p.communicate()

See docs for more details.

花间憩 2024-09-04 09:30:45

您需要等待该过程完成:

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True)
p.wait()

或者,您可以捕获程序的标准输出(如您所拥有的),也许还有它的标准错误,然后调用communicate

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True,
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()

You need to wait for the process to finish:

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True)
p.wait()

Alternatively, you can capture the program's standard output (as you have), and perhaps its standard error, and then call communicate:

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True,
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文