Перенаправить подпроцесс stderr в stdout

Я хочу перенаправить вывод stderr подпроцесса на stdout. Постоянная STDOUT должна делать это, не так ли?

Однако

$ python >/dev/null -c 'import subprocess;\
                        subprocess.call(["ls", "/404"],stderr=subprocess.STDOUT)'

выводит что-то. Почему это так, и как мне получить сообщение об ошибке на stdout?

Ответы

Ответ 1

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

subprocess.STDOUT
Специальное значение, которое (...) указывает, что стандартная ошибка должна входить в один и тот же дескриптор в качестве стандартного вывода.

Так как stdout устанавливается на "по умолчанию" (-1, технически), когда stderr=subprocess.STDOUT оценивается, stderr также устанавливается на "default". К сожалению, это означает, что вывод stderr все еще идет на stderr.

Чтобы решить проблему, перейдите в файл stdout вместо subprocess.STDOUT:

$ python >/dev/null -c 'import subprocess,sys;subprocess.call(["ls", "/404"],
                        stderr=sys.stdout.buffer)'

Или, для совместимости с устаревшими версиями версии 2.x Python:

$ python >/dev/null -c 'import subprocess,sys;subprocess.call(["ls", "/404"],
                        stderr=sys.stdout.fileno())'

Ответ 2

На самом деле, используя subprocess.STDOUT, точно, что указано в документации: перенаправляет stderr на stdout, чтобы, например,

proc = subprocess.Popen(self.task["command"], shell=False, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = ""
while (True):
    # Read line from stdout, break if EOF reached, append line to output
    line = proc.stdout.readline()
    line = line.decode()
    if (line == ""): break
    output += line

выводит вывод, содержащий вывод процесса, как из stdout, так и из stderr.

stderr=subprocess.STDOUT перенаправляет весь вывод stderr напрямую на стандартный вывод вызывающего процесса, что является существенным отличием.