Подпроцесс Python. Открыть связь через конвейер - PullRequest
1 голос
/ 11 августа 2010

Я хочу иметь возможность использовать Popen.communicate и иметь стандартный вывод, записанный в файл (в дополнение к тому, что возвращается из 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)

Любые проблемы с этим, глядя на общение, это выглядит хорошо. Но есть ли лучший способ?

1 Ответ

1 голос
/ 11 августа 2010

В зависимости от вашего определения «лучше», я бы сказал, что следующее, вероятно, лучше в том смысле, что он избегает дополнительного процесса тройника:

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(), которая записывает стандартный вывод в дескриптор файла по вашему выбору, а затем возвращает исходный кортеж для использования. Я опустил обработку исключений; Вы, вероятно, должны добавить это, если программа более критична. Кроме того, если вы ожидаете создать несколько Popen объектов и хотите, чтобы они все записывались в один и тот же файл, вам, вероятно, следует организовать logcommunicate() для обеспечения многопоточности (синхронизация по дескриптору файла). Вы можете легко расширить это решение для записи в отдельные файлы для stdout и stderr.

Обратите внимание, что если вы собираетесь передавать много данных назад и вперед, то communicate() может быть не лучшим вариантом, поскольку он буферизует все в памяти.

...