Как получить код выхода из subprocess.Popen?

В приведенном ниже коде p.returncode всегда None. Согласно Popen.returncode документации, это означает, что процесс еще не завершен.

Почему я не получаю код выхода?

import os
import sys
import subprocess

cmd = ['echo','hello']
p = subprocess.Popen(cmd,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT)
try:
    # Filter stdout
    for line in iter(p.stdout.readline, ''):
        sys.stdout.flush()
        # Print status
        print(">>> " + line.rstrip())
        sys.stdout.flush()
except:
    sys.stdout.flush()

print 'RETURN CODE', p.returncode

Обратите внимание: причина, по которой я читаю каждую строку отдельно, заключается в том, что я хочу фильтровать выходные данные других длительных процессов в режиме реального времени и останавливать их на основе определенных строк.

Я на Python 2.7.5 (CentOS 7 64-бит).


Решение

Благодаря ответу, отправленному @skyking, теперь я могу успешно захватить код выхода следующим образом: Popen.poll() (Popen.wait() заблокировал мой процесс):

import os
import sys
import subprocess
import time

cmd = ['echo','hello']
p = subprocess.Popen(cmd,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT)
try:
    # Filter stdout
    for line in iter(p.stdout.readline, ''):
        sys.stdout.flush()
        # Print status
        print(">>> " + line.rstrip())
        sys.stdout.flush()
except:
    sys.stdout.flush()

# Wait until process terminates (without using p.wait())
while p.poll() is None:
    # Process hasn't exited yet, let wait some
    time.sleep(0.5)

# Get return code from process
return_code = p.returncode

print 'RETURN CODE', return_code

# Exit with return code from process
sys.exit(return_code)

Ответы

Ответ 1

В соответствии с документацией

Код возврата ребенка, установленный poll() и wait() (и косвенно  общаться()). Значение None указывает, что процесс еще не завершился.

Отрицательное значение -N указывает, что ребенок был прерван сигналом N (только для Unix).

Вы не вызывали poll или wait, поэтому returncode не будет установлен.

С другой стороны, если вы посмотрите на исходный код для fx check_output, вы увидите, что они напрямую используют возвращаемое значение из poll для проверки кода возврата. Они знают, что процесс завершился в этот момент, потому что они раньше называли wait. Если вы не знаете, что вам придется называть метод wait вместо этого (но обратите внимание на ту тупиковую возможность, отмеченную в документации).

Обычно программа прекращается, когда вы читаете все stdout/stderr, но это не гарантируется, и это может быть то, что вы видите. Либо программа, либо ОС могут закрыть stdoutstderr) до того, как процесс действительно завершится, а затем просто позвонив poll сразу после того, как вы прочитали все выходные данные программы, могут выйти из строя.