2010-02-25 1 views
34

Мне нужно запустить ряд длительных процессов с subprocess.Popen и хотел бы иметь stdout и stderr от каждого автоматически подключенного к отдельным файлам журнала. Каждый процесс будет запускаться одновременно в течение нескольких минут, и я хочу два файла журнала (stdout и stderr) за процесс, который будет записан в качестве процессов.вывод трубопровода подпроцесса. Открытие файлов

Нужен ли мне постоянно звонить p.communicate() на каждом процессе в цикле, чтобы обновить каждый файл журнал, или есть какой-то способ, чтобы вызвать оригинальную Popen команды так, чтобы stdout и stderr автоматически потоковом открывать дескрипторы файлов?

ответ

34

Per the docs,

STDIN, STDOUT и STDERR указать выполняемые программы стандартный ввод, стандартный вывод и стандартная ошибка файлы, соответственно. Допустимыми значениями являются PIPE, существующий файл дескриптор (положительное целое число), существующий файловый объект и None.

Так просто передать открытым для написания файловых объектов, как именованные аргументы stdout= и stderr= и вы должны быть хорошо!

+0

Спасибо. Я мог бы поклясться, что пробовал это раньше и получил ошибку, но это именно то, на что я надеялся работать. – 2010-02-25 04:53:33

+0

Это не работает для меня. Я одновременно запускаю два процесса и сохраняю stdout и stderr из одного в один файл журнала. Если выход становится слишком большим, один из подпроцессов висит; не знаю, какой. Я не могу использовать форматирование в комментарии, поэтому я добавлю «ответ» ниже. – jasper77

53

Вы можете передать stdout и stderr в качестве параметров для Popen()

subprocess.Popen(self, args, bufsize=0, executable=None, stdin=None, stdout=None, 
       stderr=None, preexec_fn=None, close_fds=False, shell=False, 
       cwd=None, env=None, universal_newlines=False, startupinfo=None, 
       creationflags=0) 

Например

>>> import subprocess 
>>> with open("stdout.txt","wb") as out, open("stderr.txt","wb") as err: 
... subprocess.Popen("ls",stdout=out,stderr=err) 
... 
<subprocess.Popen object at 0xa3519ec> 
>>> 
+3

Woa! Я понятия не имел, что вы можете так просто «открыть» в менеджере контекста. #mindblown – hwjp

+0

Не работает для меня! 'with open (" server.log "," wb ") как вне: sp.call (server_cmd, stdout = out)' – Ayush

2

Я одновременно запускаю два подпроцесса и сохраняю вывод обоих файлов в один файл журнала. Я также построил тайм-аут для обработки подпроцессов подвешенных. Когда выход становится слишком большим, тайм-аут всегда запускается, и ни один из stdout из любого подпроцесса не сохраняется в файле журнала. Ответ, поставленный Алексом выше, не решает его.

# Currently open log file. 
log = None 

# If we send stdout to subprocess.PIPE, the tests with lots of output fill up the pipe and 
# make the script hang. So, write the subprocess's stdout directly to the log file. 
def run(cmd, logfile): 
    #print os.getcwd() 
    #print ("Running test: %s" % cmd) 
    global log 
    p = subprocess.Popen(cmd, shell=True, universal_newlines = True, stderr=subprocess.STDOUT, stdout=logfile) 
    log = logfile 
    return p 


# To make a subprocess capable of timing out 
class Alarm(Exception): 
    pass 

def alarm_handler(signum, frame): 
    log.flush() 
    raise Alarm 


#### 
## This function runs a given command with the given flags, and records the 
## results in a log file. 
#### 
def runTest(cmd_path, flags, name): 

    log = open(name, 'w') 

    print >> log, "header" 
    log.flush() 

    cmd1_ret = run(cmd_path + "command1 " + flags, log) 
    log.flush() 
    cmd2_ret = run(cmd_path + "command2", log) 
    #log.flush() 
    sys.stdout.flush() 

    start_timer = time.time() # time how long this took to finish 

    signal.signal(signal.SIGALRM, alarm_handler) 
    signal.alarm(5) #seconds 

    try: 
    cmd1_ret.communicate() 

    except Alarm: 
    print "myScript.py: Oops, taking too long!" 
    kill_string = ("kill -9 %d" % cmd1_ret.pid) 
    os.system(kill_string) 
    kill_string = ("kill -9 %d" % cmd2_ret.pid) 
    os.system(kill_string) 
    #sys.exit() 

    end_timer = time.time() 
    print >> log, "closing message" 

    log.close()