2016-06-07 14 views
0

Nehmen Sie diesen Code als Beispiel (tar durch -z -J -j komprimieren kann, und es gibt ein tarfile spezifisches Modul, ich weiß, aber es ist eine lange laufenden Prozess darstellen)Wie kann ich überprüfen, ob einer von zwei Piped Subprozess in Python fehlschlägt?

from subprocess import Popen, PIPE 
    with open('tarball.tar.gz', 'w+') as tarball: 
     tarcmd = Popen(['tar', '-cvf', '-', '/home'], stdout=PIPE) 
     zipcmd = Popen(['gzip', '-c'], stdin=tarcmd.stdout, stdout=tarball) 
     tarcmd.stdout.close() 
     zipcmd.communicate() 
     # added a while loop that breaks when tarcmd gets a 
     # proper return value. Can it be considerate a good 
     # solution? 
     while tarcmd.poll() is None: 
      print('waiting...') 

     # test the values and do stuff accordingly 

Dies ist die typische Beispiel für die Übergabe von zwei Befehlen im Python-Subprozess. Jetzt ist es einfach, den Rückgabecode von zipcmd zu überprüfen, aber wie kann man überprüfen, ob tarcmd fehlschlägt? wenn ich seinen Returncode überprüfe, bekomme ich immer keinen (ich denke, weil stdout geschlossen ist). Grundsätzlich möchte ich eine Ausnahme auslösen, wenn einer der beiden Befehle fehlschlägt. In bash gibt es $ PIPESTATUS, wie kann ich das in Python machen?

+0

Von Dokumentation des Subprozess-Modul, über Prozesse Rückkehr Überprüfung: A Kein Wert zeigt an, dass der Prozess noch nicht beendet hat. Ihr tarcmd wird noch ausgeführt ODER Sie haben das Ergebnis nicht überprüft. Warten Sie, bis es mit .wait() oder .poll() beendet wird. Mit diesen Methoden wird der korrekte Rückgabewert festgelegt. – Maciek

+0

Danke, ich habe eine While-Schleife hinzugefügt, die bricht, wenn tarcmd einen passenden Returncode bekommt und es scheint jetzt zu funktionieren! (Es kann eine gute Lösung sein?). Ich habe auch versucht, tarcmd.communicate(), aber es funktioniert nicht. Wenn ich es nach tar.stdout.close() setze, ob der Befehl fehlschlägt oder es gelingt, bekomme ich immer einen "ValueError: I/O-Vorgang bei geschlossener Datei". Wenn ich es vor tar.stdout.close() lege, da communicate() wartet, bis der Befehl beendet ist, wird stdout nicht geschlossen und erlaubt dem tarcmd nicht, ein sigpipe zu erhalten, wenn gzip vorzeitig beendet wird. Jede weitere Hilfe wird geschätzt – Egidiux

Antwort

0

if i check its returncode i always get none

Wenn der Wert None dann bedeutet es, dass der entsprechende Kind-Prozess noch am Leben ist. Übrigens, es besteht keine Notwendigkeit, tarcmd.poll() in einer Schleife aufzurufen. Sie können blockieren, bis es mit tarcmd.wait() beendet wird.

Es ist weniger fehleranfällig die Shell-Pipeline zu emulieren:

#!/usr/bin/env python 
from subprocess import check_call 

check_call('set -e -o pipefail; tar -cvf - /home | gzip -c > tarball.tar.gz', 
      shell=True, executable='/bin/bash') 

durch Umkehrung des Prozesses Initialisierungsreihenfolge:

#!/usr/bin/env python 
from subprocess import Popen, PIPE 

with open('tarball.tar.gz', 'wb', 0) as tarball_file: 
    gzip = Popen(['gzip', '-c'], stdin=PIPE, stdout=tarball_file) 
tar = Popen(['tar', '-cvf', '-', '/home'], stdout=gzip.stdin) 
gzip.communicate() 
if tar.wait() != 0 or gzip.returncode != 0: 
    raise CalledProcessError 

Es ist einfacher könnte entweder shell=True zu verwenden (wenn der Befehl erstellt aus einer vertrauenswürdigen Eingabe wie einem String-Literal in Ihrer Quelldatei) oder verwenden Sie eine Bibliothek wie plumbum, um die Pipeline auszuführen, anstatt sie direkt über Popen zu implementieren.

#!/usr/bin/env python 
from plumbum.cmd import gzip, tar 

(tar['-cvf', '-', '/home'] | gzip['-c'] > 'tarball.tar.gz')() 

Siehe How do I use subprocess.Popen to connect multiple processes by pipes?