it-swarm.com.de

Exit-Code und stderr vom Unterprozess-Aufruf abrufen

Ich habe mich über die Funktionen informiert, die durch den Unterprozess bereitgestellt werden - call, check_call, check_output - und verstehe, wie die einzelnen Funktionen funktionieren und sich in ihrer Funktionalität voneinander unterscheiden. Ich verwende derzeit check_output, damit ich auf stdout zugreifen kann, und benutze "try block", um die Ausnahme abzufangen, wie folgt:

# "cmnd" is a string that contains the command along with it's arguments. 
try:
    cmnd_output = check_output(cmnd, stderr=STDOUT, Shell=True, timeout=3, universal_newlines=True);                         
except CalledProcessError:                                                                                                   
    print("Status : FAIL")                                                                                                   
print("Output: \n{}\n".format(cmnd_output))                                                                                  

Das Problem, auf das ich stoße, ist, wenn eine Ausnahme ausgelöst wird, "cmnd_output" nicht initialisiert wird und keinen Zugriff auf stderr hat, und folgende Fehlermeldung angezeigt wird:

print("Output: \n{}\n".format(cmnd_output))
UnboundLocalError: local variable 'cmnd_output' referenced before assignment

Ich denke, das liegt daran, dass die Ausnahme bewirkt, dass "check_output" ohne weitere Verarbeitung, auch bekannt als "cmnd_output" -Zuweisung, im try-Block sofort ausfällt. Bitte korrigieren Sie mich, wenn ich falsch liege.

Kann ich auf irgendeine Weise auf stderr zugreifen (es ist in Ordnung, wenn es an stout gesendet wird) und Zugriff auf den Beendigungscode haben? Ich kann anhand des Exit-Codes manuell nach Pass/Fail suchen, ohne dass eine Ausnahme vorliegt.

Danke, Ahmed.

58
Ahmed A

Versuchen Sie diese Version:

import subprocess
try:
    output = subprocess.check_output(
        cmnd, stderr=subprocess.STDOUT, Shell=True, timeout=3,
        universal_newlines=True)
except subprocess.CalledProcessError as exc:
    print("Status : FAIL", exc.returncode, exc.output)
else:
    print("Output: \n{}\n".format(output))

Auf diese Weise drucken Sie die Ausgabe nur, wenn der Aufruf erfolgreich war. Bei einem CalledProcessError geben Sie den Returncode und die Ausgabe aus.

87
warvariuc

Die akzeptierte Lösung deckt den Fall ab, dass Sie in Ordnung sind, stdout und stderr zu mischen, aber in Fällen, in denen der untergeordnete Prozess (aus welchen Gründen auch immer) beschließt, stderr IN ADDITION zu verwenden auf stdout für eine nicht fehlgeschlagene Ausgabe (dh um eine nicht kritische Warnung auszugeben), ist die angegebene Lösung möglicherweise nicht wünschenswert.

Wenn Sie beispielsweise zusätzliche Verarbeitungsschritte für die Ausgabe ausführen, z. B. die Konvertierung in JSON, und das stderr einmischen, schlägt der Gesamtprozess fehl, da die Ausgabe aufgrund des hinzugefügten stderr Ausgabe.

In diesem Fall hat Folgendes funktioniert:

cmd_args = ... what you want to execute ...

pipes = subprocess.Popen(cmnd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
std_out, std_err = pipes.communicate()

if pipes.returncode != 0:
    # an error happened!
    err_msg = "%s. Code: %s" % (std_err.strip(), pipes.returncode)
    raise Exception(err_msg)

Elif len(std_err):
    # return code is 0 (no error), but we may want to
    # do something with the info on std_err
    # i.e. logger.warning(std_err)

# do whatever you want with std_out
# i.e. json.loads(std_out)
52
oarevalo

Beide vorgeschlagenen Lösungen mischen entweder stdout/stderr oder verwenden Popen, was nicht ganz so einfach zu verwenden ist wie check_output. Sie können jedoch dasselbe erreichen und stdout/stderr getrennt halten, während Sie check_output Verwenden, wenn Sie einfach stderr erfassen mit einer Pipe:

import sys
import subprocess

try:
    subprocess.check_output(cmnd, stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
    print('exit code: {}'.format(e.returncode))
    print('stdout: {}'.format(e.output.decode(sys.getfilesystemencoding())))
    print('stderr: {}'.format(e.stderr.decode(sys.getfilesystemencoding())))

Da wir in diesem Beispiel stderr erfasst haben, ist es im stderr -Attribut der Ausnahme verfügbar (ohne Erfassung mit der Pipe wäre es nur None).

5
Kyle