2012-07-15 20 views
24

Chcę przekierować wyjście stderr podprocesu na standardowe wyjście. Stała STDOUT powinna to zrobić, czyż nie?Przekierowanie podprocesu stderr na stdout

Jednak

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

robi wyjściowy coś. Dlaczego tak jest i jak mogę uzyskać komunikat o błędzie na standardowe wyjście?

+0

BTW, naprawiono to w pythonie 3.5. – max

Odpowiedz

29

Dokładne przeczytanie source code daje odpowiedź. W szczególności documentation jest mylące, gdy mówi:

subprocess.STDOUT
wartość specjalna, że ​​(...) wskazuje, że błąd standardowy powinien iść do tego samego uchwytem jako standardowe wyjście.

Od stdout jest ustawiony na "default" (-1 technicznie), gdy stderr=subprocess.STDOUT ocenia, stderr jest ustawiony na "default", jak również. Niestety oznacza to, że wyjście stderr nadal idzie na stderr.

Aby rozwiązać ten problem, należy przejść do pliku stdout zamiast subprocess.STDOUT:

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

Albo, dla kompatybilności z wersjami dziedzictwo 2.x Pythona:

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

Można opuścić stderr jako -to też: 'stderr = sys.stderr.fileno()'. Dobry przykład; Zamierzam po prostu użyć tej techniki we wszystkich moich skryptach. Mamy starszy Python 2.x; dzięki temu będę wiedział dokładnie, gdzie powiedziałem, aby przejść bez zamieszania. –

6

Właściwie nie używając subprocess.STDOUTdokładnie co jest określone w dokumentacji: przekierowuje stderr na standardowe wyjście, aby np.

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 

wyniki w wynikach zawierających dane wyjściowe procesu zarówno z wyjścia standardowego, jak i standardowego.

stderr=subprocess.STDOUT przekierowuje wszystkie wyjścia stderr bezpośrednio na stdout procesu wywołującego, co jest główną różnicą.

+0

-1 Ta sprawa nie ma znaczenia dla pytania, które dotyczy 'stdout' oznaczającego' Brak'. Natomiast 'subprocess.STDOUT' nie przekierowuje do" konsoli wywołującej "(myślę, że masz na myśli uchwyt pliku 1, który został podany w bieżącym procesie), jak pokazuje twój własny przykład - jeśli wywołasz Popena z' ['ls', '/404 '] ', komunikat o błędzie nie jest wyświetlany (http://ideone.com/2JhcRT). – phihag

+0

Masz trochę racji. Jednak nie sądzę, aby było to w ogóle nieistotne, ponieważ ma to na celu wyjaśnienie twojego stanowiska dotyczącego wprowadzającej w błąd dokumentacji - co nie jest prawdą. Zostawiłbym komentarz pod twoim postem, ale rok temu nie mogłem tego zrobić. – Maxxim

+0

'python -c 'importuj podproces, sys; subprocess.call ([" ls ","/404 "], stderr = podproces.STDOUT)' 2>/dev/null' pokazuje, że stderr' ls' idzie na stderr (deskryptor pliku 2), ponieważ nie zobaczysz żadnego wyjścia (zakładając, że nie masz '/ 404' w twoim systemie). Ta dokumentacja Pythona naprawdę wciągnęła na ten temat, i jest to szczególnie denerwujące dla nas, programistów skryptów, którzy są przyzwyczajeni do manipulowania stdout/stderr na miriady sposobów, i muszą przyjść tutaj do SO, aby dowiedzieć się, jak zrobić coś, co powinno być proste i niezrozumiały. –

Powiązane problemy