Как зафиксировать промежуточную ошибку в конвейерном выполнении подпроцесса Python - PullRequest
0 голосов
/ 09 ноября 2018

После python doc для замены shell-конвейера у меня есть фрагмент кода, который выглядит следующим образом.

p1 = Popen(["tac" , "/var/log/some_process_log.output"], stderr=PIPE, stdout=PIPE)
p2 = Popen(["head", "-n", "1000"], stdin=p1.stdout, stdout=outfile)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

outfile - это место, где я хочу перенаправить выводhead команда.Файл журнала очень большой, и поэтому я делаю над ним 'head'

Цепочка похожа на p1 | p2 | p3 | ..... | Pn > outfile

Если есть ошибка при выполнении p1, например, у пользователя нетразрешения на чтение для файла /var/log/some_process_log.output, сообщение об ошибке в p1.stderr не передается по конвейеру, когда я выполняю Pn.communicate()

Если я выполняю p1.stderr.readline () на каждом этапе, тогда требуется долгое время обрабатывать .Это упоминается в pydocs:

Примечание. Считываемые данные буферизируются в памяти, поэтому не используйте этот метод, если размер данных большой или неограниченный.

Яизбегая subprocess.check_output, так как он не обрабатывает трубопроводы, а также нуждается в небезопасном shell=True

Любая помощь будет принята с благодарностью.Спасибо

1 Ответ

0 голосов
/ 09 ноября 2018

Вы можете создать отдельную трубу с помощью:

import os
errread, errwrite = os.pipe()

И установите конец записи как stderr для всех ваших Popen экземпляров:

p1 = Popen(["tac" , "/var/log/some_process_log.output"], stderr=errwrite, stdout=PIPE)
p2 = Popen(["head", "-n", "1000"], stdin=p1.stdout, stderr=errwrite, stdout=outfile)

Не забудьте закрыть конец записи, когда это будет сделано:

os.close(errwrite)

И получите ваши сообщения об ошибках:

data_group = os.read(errread, buf_size)

или

import io
data = io.open(errread, 'rb', buf_size).read()
...