subprocess: Output und Error-Code verarbeiten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
graceflotte
User
Beiträge: 25
Registriert: Samstag 8. März 2014, 12:17

Moin,

ich habe folgenes Problem:
Aktuell schreibe ich den Output aller Kanäle von ls in eine Datei, um Sie später wieder zu lesen.

Code: Alles auswählen

subLs = subprocess.Popen("ls > /tmp/lsOutput 2>&1",shell=True)
errCode = subLs.wait()
Da mir das aber recht unschön erschien habe ich es nun anders gelöst:

Code: Alles auswählen

lsOutput = subprocess.check_output(['ls'])
Das Ganze hat jetzt nur halt den Haken, dass ich nicht weiß, wie ich an den Error-Code komme, da lsOutput ja ein String ist und kein Objekt. Habt ihr da eine Idee? Danke ;)
BlackJack

@graceflotte: Das geht mit `check_output()` nicht. Das Unchöne an der ersten Lösung ist IMHO das Du eine Shell dazwischen schaltest um die Ausgaben umzuleiten, und dann auch noch in eine Datei, statt das über das `Popen`-Objekt zu machen und die Ausgaben zu PIPEn. Also ungetestet:

Code: Alles auswählen

from subprocess import PIPE, Popen, STDOUT

    # ...
    process = Popen(['ls'], stdout=PIPE, stderr=STDOUT)
    output, _ = process.communicate()
    error_code = process.wait()
graceflotte
User
Beiträge: 25
Registriert: Samstag 8. März 2014, 12:17

ok, danke ;)

Was hat es mit dem Unterschrich in Zeile 5 auf sich?
Schorlem
User
Beiträge: 40
Registriert: Dienstag 3. Juni 2014, 16:37

@graceflotte Da Popen.communicate() zwei Werte (stdoutdata, stderrdata) zurückgibt und der zweite nicht gebraucht wird, nimmt man meist den Unterstrich statt eines "normalen" Variablennamens, wenn man den Rückgabewert nicht weiter verwenden will.
Diese Nachricht wurde maschinell erstellt und ist daher ohne Unterschrift gültig.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@graceflotte: Was Schorlem gesagt hat. Ergänzend dazu: der Unterstrich ist für den Programmierer da, nicht für Python. Für Python ist er ein ganz normaler Name, aber dem Programmierer zeigt er an, was Schorlem erläutert hat.

Nur am Python-Prompt bedeutet er etwas anderes:

Code: Alles auswählen

>>> 3 + 5
8
>>> _
8
D.i. der Wert des zuletzt ausgewerteten Ausdrucks.
In specifications, Murphy's Law supersedes Ohm's.
graceflotte
User
Beiträge: 25
Registriert: Samstag 8. März 2014, 12:17

Ah, ok. Vielen Dank :)

Nur aus neugier: Wie sieht soeine Funktion mit mehreren Return-Werten aus?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Jede Funktion hat genau einen Rückgabewert, dieser kann jedoch beliebig komplex sein.

Code: Alles auswählen

return 23, 42
gibt genau einen Wert zurück, nämlich das Tupel (23, 42). Der Trick mit dem ``output, _ = process.communicate()`` nennt sich Tuple-Unpacking. Damit kannst du ein Tupel in seine Bestandteile zerlegen:

Code: Alles auswählen

t = 23, 42, 99
x, y, z = t
Das ist einfach kurz für

Code: Alles auswählen

x = t[0]
y = t[1]
z = t[2]
Das Leben ist wie ein Tennisball.
graceflotte
User
Beiträge: 25
Registriert: Samstag 8. März 2014, 12:17

@EyDu
Und wieder was gelernt. Danke ;)


Noch eine letzte Frage: PIPE gibt an, dass der Output nicht ausgegeben werden soll?
BlackJack hat geschrieben:@graceflotte: Das geht mit `check_output()` nicht. Das Unchöne an der ersten Lösung ist IMHO das Du eine Shell dazwischen schaltest um die Ausgaben umzuleiten, und dann auch noch in eine Datei, statt das über das `Popen`-Objekt zu machen und die Ausgaben zu PIPEn. Also ungetestet:

Code: Alles auswählen

 process = Popen(['ls'], stdout=PIPE, stderr=STDOUT)
BlackJack

@graceflotte: ``stdout=PIPE`` gibt an wo die Standardausgabe von dem externen Prozess hingeschrieben werden soll. In diesem Fall in eine „pipe” die mit dem aufrufenden Prozess verbunden ist und auf dem `Popen()`-Objekt als Dateiobjekt als Attribut `stdout` verfügbar ist. Da kann man die Ausgabe dann auslesen. Was `communicate()` intern für einen erledigt. Man hätte an der Stelle auch ``process.stdout.read()`` verwenden können.
graceflotte
User
Beiträge: 25
Registriert: Samstag 8. März 2014, 12:17

Vielen Dank.

Wie verwirkliche ich Befehle mit Pipe?

also z.B.

Code: Alles auswählen

ls | grep 'loop'
BlackJack

@graceflotte: Zwei `Popen`-Prozesse starten und dabei die Ausgabe von einem mit der Eingabe des anderen verbinden. Wobei man auch immer schauen sollte ob man die externen Programme überhaupt braucht. Das war wahrscheinlich nur ein Beispiel, aber *das* würde man sicher besser in Python schreiben statt externe Programme zu starten.
graceflotte
User
Beiträge: 25
Registriert: Samstag 8. März 2014, 12:17

Wie würde man das dann in Python umsetzten?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ein erster Anfang ist immer der Blick in die Dokumentation des entsprechenden Moduls. Angeblich enthält die Dokumentation sogar ein Beispiel zu genau diesem Thema. Habe ich mal so gehört ;-)
Das Leben ist wie ein Tennisball.
BlackJack

Code: Alles auswählen

from __future__ import print_function
import os


def main():
    for filename in os.listdir(os.curdir):
        if 'loop' in filename:
            print(filename)


if __name__ == '__main__':
    main()
Oder habe ich die Frage jetzt falsch verstanden? :-)
graceflotte
User
Beiträge: 25
Registriert: Samstag 8. März 2014, 12:17

Ne, passt schon. Danke ;)
Antworten