Сохранение стандартного вывода из подпроцесса. Открыть в файл, а также записать дополнительные данные в файл - PullRequest
19 голосов
/ 07 июля 2010

Я пишу скрипт на python, который использует subprocess.Popen для выполнения двух программ (из скомпилированного кода C), каждая из которых выдает стандартный вывод. Сценарий получает этот вывод и сохраняет его в файл. Поскольку выходные данные иногда достаточно велики, чтобы перегружать подпроцесс. PIPE, из-за чего скрипт зависает, я посылаю stdout непосредственно в файл журнала. Я хочу, чтобы мой сценарий записывал что-то в начало и конец файла, а также между двумя вызовами подпроцесса. Открыть. Однако, когда я смотрю на мой файл журнала, все, что я записал в файл журнала из сценария, все вместе находится вверху файла, за которым следует весь исполняемый стандартный вывод. Как я могу чередовать мой добавленный текст в файл?

def run(cmd, logfile):
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile)
    return p

def runTest(path, flags, name):
    log = open(name, "w")
    print >> log, "Calling executable A"
    a_ret = run(path + "executable_a_name" + flags, log)
    print >> log, "Calling executable B"
    b_ret = run(path + "executable_b_name" + flags, log)
    print >> log, "More stuff"
    log.close()

Файл журнала имеет: Вызов исполняемого файла A Вызов исполняемого файла B Больше вещей [... стандартный вывод из обоих исполняемых файлов ...]

Можно ли, например, сбросить стандартный вывод A в журнал после вызова Popen? Еще одна вещь, которая может иметь значение: запускается исполняемый файл A, затем ожидает B, а после того, как B печатает материал и заканчивает, A затем печатает больше материала и заканчивает.

Я использую Python 2.4 на RHE Linux.

Ответы [ 4 ]

20 голосов
/ 07 июля 2010

Вы можете вызвать .wait () для каждого объекта Popen, чтобы убедиться, что он завершен, а затем вызвать log.flush ().Может быть что-то вроде этого:

def run(cmd, logfile):
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile)
    ret_code = p.wait()
    logfile.flush()
    return ret_code

Если вам нужно взаимодействовать с объектом Popen во внешней функции, вы можете вместо этого переместить туда вызов .wait ().

2 голосов
/ 22 ноября 2012

Насколько я понимаю, A программа ждет, пока B сделает свое дело, и A завершится только после выхода B.

Если B может запуститься без запуска A, тоВы можете запустить процессы в обратном порядке:

from os.path import join as pjoin
from subprocess import Popen

def run_async(cmd, logfile):
    print >>log, "calling", cmd
    p = Popen(cmd, stdout=logfile)
    print >>log, "started", cmd
    return p

def runTest(path, flags, name):
    log = open(name, "w", 1)  # line-buffered
    print >>log, 'calling both processes'
    pb = run_async([pjoin(path, "executable_b_name")] + flags.split(), log)
    pa = run_async([pjoin(path, "executable_a_name")] + flags.split(), log)
    print >>log, 'started both processes'
    pb.wait()
    print >>log, 'process B ended'
    pa.wait()
    print >>log, 'process A ended'
    log.close()

Примечание: вызов log.flush() в основных процессах не влияет на файловые буферы в дочерних процессах.

Если дочерние процессы используют буферизацию блоков для stdout, вы можете попытаться заставить их сбрасываться раньше, используя pexpect, pty или stdbuf (предполагается, что процессы используют буферизацию строк при запускеинтерактивно или они используют библиотеку C stdio для ввода / вывода).

2 голосов
/ 08 июля 2010

Я говорю, просто будь проще. Базовая логика псевдокода:

write your start messages to logA
execute A with output to logA
write your in-between messages to logB
execute B with output to logB
write your final messages to logB
when A & B finish, write content of logB to the end of logA
delete logB
2 голосов
/ 07 июля 2010

Вам нужно дождаться окончания процесса, прежде чем продолжить. Я также преобразовал код, чтобы использовать менеджер контекста, который чище.

def run(cmd, logfile):
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile)
    p.wait()
    return p

def runTest(path, flags, name):
    with open(name, "w") as log:
        print >> log, "Calling executable A"
        a_ret = run(path + "executable_a_name" + flags, log)
        print >> log, "Calling executable B"
        b_ret = run(path + "executable_b_name" + flags, log)
        print >> log, "More stuff"
...