Python subprocess.Popen 通过管道通信

1 投票
1 回答
4668 浏览
提问于 2025-04-16 02:37

我想使用 Popen.communicate,并且希望把标准输出(stdout)记录到一个文件里(除了从 communicate() 返回的内容)。

这样做可以达到我的目的,但这样真的好吗?

cat_task = subprocess.Popen(["cat"],  stdout=subprocess.PIPE, stdin=subprocess.PIPE)
tee_task = subprocess.Popen(["tee", "-a", "/tmp/logcmd"], stdin=cat_task.stdout, 
    stdout = subprocess.PIPE, close_fds=True)
cat_task.stdout = tee_task.stdout #since cat's stdout is consumed by tee, read from tee.
cat_task.communicate("hello there")
('hello there', None)

这样做有没有什么问题?看了 communicate 的实现,感觉还不错。但是有没有更好的方法呢?

1 个回答

1

根据你对“更好”的定义,我觉得下面这个方法可能更好,因为它避免了额外的tee进程:

import subprocess

def logcommunicate(self, s):
    std = self.oldcommunicate(s)
    self.logfilehandle.write(std[0])
    return std

subprocess.Popen.oldcommunicate = subprocess.Popen.communicate
subprocess.Popen.communicate = logcommunicate
logfh = open("/tmp/communicate.log", "a")

proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
proc.logfilehandle = logfh

result = proc.communicate("hello there\n")
print result

简单来说,它为communicate()提供了一个包装,这个包装会把标准输出(stdout)写入你选择的文件中,然后返回原来的结果给你使用。我省略了异常处理;如果这个程序比较重要,你可能需要加上这部分。另外,如果你打算创建多个Popen对象,并希望它们都记录到同一个文件中,你可能需要确保logcommunicate()是线程安全的(也就是说,针对每个文件句柄进行同步)。你也可以很容易地扩展这个方法,让标准输出和标准错误(stderr)写入不同的文件。

需要注意的是,如果你预计会频繁传输大量数据,那么communicate()可能不是最佳选择,因为它会把所有数据都保存在内存中。

撰写回答