Подтвердить что ты не робот

Сохранение stdout из subprocess.Popen в файл, плюс запись большего количества материала в файл

Я пишу python script, который использует subprocess.Popen для выполнения двух программ (из скомпилированного кода C), каждый из которых производит stdout. script получает этот вывод и сохраняет его в файл. Поскольку выход иногда достаточно велик, чтобы перегружать subprocess.PIPE, в результате чего w370 > зависает, я отправляю stdout непосредственно в файл журнала. Я хочу, чтобы мой script записывал что-то в начало и конец файла и между двумя вызовами subprocess.Popen. Однако, когда я смотрю на свой файл журнала, все, что я написал в файл журнала из script, находится вместе в верхней части файла, за которым следует весь исполняемый файл 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 Больше вещей [... stdout из обоих исполняемых файлов...]

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

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

4b9b3361

Ответ 1

Вы можете вызвать .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

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

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"

Ответ 3

Я говорю, просто держи это просто. Основная логика псевдокода:

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

Ответ 4

Как я понимаю, программа 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 для ввода-вывода).