Probleme mit "subprocess"

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
walkingshadow
User
Beiträge: 4
Registriert: Dienstag 7. März 2006, 19:17
Wohnort: Düdelingen / Luxemburg
Kontaktdaten:

Hallo!
Ich habe ein Problem mit dem Standardmodul "subprocess". Ich bin dabei eine grafische Orberfläche für die "ports collection" von FreeBSD zu schreiben, ein grafisches Tool auf Basis von gtk2 um Software Pakete zu verwalten. Das Tool führt alle benötigten Programme wi z.B. "make" aus und schreibt alles was ausgegeben wurde in eine textview. Um auf die Standardausgabe der Kommandozeilenprogramme zuzugreifen benutze ich eine Klasse die ich hier gefunde habe: http://aspn.activestate.com/ASPN/Cookbo ... ipe/440554
Problematisch wird es wenn der unterprozess selbst einen unterprozess aufruft. Um zum Beispiel Software upzudaten wird unter FreeBSD üblicherweise portupgrade benutzt. Dies ist eine sammlung von Ruby scripten welche alles tun was nötig ist um Programme upzudaten. Rufe ich portupgrade auf bekomme ich in der Standardausgabe nur den Text der von portupgrade selbst ausgegeben wurde. portupgrade ruft make auf aber ich sehe nichts davon. Wenn ich portupgrade in der shell aufrufe sehe ich die ausgabe von make, in meinem programm in der textbox jedoch nicht.
So sieht das dann aus: http://webplaza.pt.lu/mpjjjjsj/files/sc ... -19h38.png
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Nur mal so geraten: Vielleicht gibt dieses portupgrade seine Ausgaben auf verschiedenen Kanälen aus? (stdout und stderr)

Wenn das nicht hilft, hast du schonmal shell=True versucht? Damit sollte sich das Popen wesentlich shell-ähnlicher verhalten, vielleicht hilft das ja.

Henning
walkingshadow
User
Beiträge: 4
Registriert: Dienstag 7. März 2006, 19:17
Wohnort: Düdelingen / Luxemburg
Kontaktdaten:

Hi! Vielen Dank für deine Antwort aber das Problem kann nicht von da aus kommen da ich Popen so aufrufe:
Popen(args, stdin=PIPE, stdout=PIPE, stderr=STDOUT, shell=True)

alles was in stderr geschrieben wird sollte also nach stdout weitergeleitet werden.
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Kann es einfach sein dass die Ausgabe nicht an stdout oder stdin geschickt wird, sondern irgendein Prozess der beim portupgrade aufgerufen wird das Terminal an das er gebunden ist neu öffnet (sprich sowas wie ssh macht um das Kennwort abzufragen, oder su auch macht um zu verhindern dass ein Prozess das Kennwort eingeben kann)? Das würde mich zwar wundern (weil's im Endeffekt keinen Sinn macht sowas zu tun, da portupgrade ja normalerweise ohne root-Kennwort auskommen müsste, da Du ja eh root bist wenn Du es ausführst), aber es wäre das einzige was ich mir vorstellen könnte was da passieren kann. Zumindest su öffnet stdin und out neu vom entsprechenden Terminal an das es gebunden ist, und vererbt diese Verbindung auch weiter an seine Kindprozesse als stdin und -out, soweit ich weiß.

Du kannst sonst auch noch mal probieren mit close_fds=True zu arbeiten, so dass der Kindprozess die ganzen anderen Filedeskriptoren deines "Mutter-"Prozesses (also im Endeffekt auch das echte stdin/stdout Deines Prozesses) nicht mehr mitvererbt bekommt (was ja beim fork() passiert). Aber, an sich sollte das nichts ausmachen... Da ist es schon eher wahrscheinlich dass sowas wie ich im ersten Absatz angedeutet habe passiert; in diesem Fall müsstest Du mit dem pty-Modul arbeiten. Das ist leider bei weitem nicht so angenehm wie subprocess, aber wahrscheinlich, gerade wenns daran scheitert, unvermeidlich...
--- Heiko.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

@waklinshadow: Hast du mal sowas wie
portupgrade > datei1 2> datei2
probiert?
Dann weisst du naemlich, was alles an stdout und stderr geht, und was also in deinem Programm so ankommen muss. Bei ssh zum Beispiel kann man da sehen, dass die Passwordabfrage weder an stderr noch an stdout geschickt wird, wie modelnine schon sagte.
walkingshadow
User
Beiträge: 4
Registriert: Dienstag 7. März 2006, 19:17
Wohnort: Düdelingen / Luxemburg
Kontaktdaten:

Hmmm, wenn ich aus der Bourne Shell
portupgrade > datei1 2> datei2
aufrufe bekomme ich die ganze Ausgabe von make in datei1 und nur vereinzelte Meldungen in datei2. Die Meldungen aus datei2 kann ich auch in der Textbox in meinem Programm nachlesen. Ich habe die Vermutung als würde portupgrade nachsehen ob es in einer interaktiven shell gestartet wird oder nicht und dementsprechend in einer nicht-interaktiven shell nur eine Kurzfassung ausgeben würde. Ich habe dieses Problem auch mit dem Tool portsnap welches die Ports Collection selbst (also vor allem die Makefiles) aktualisiert. Wenn ich "portsnap fetch" aus der shell ausführe bekomme ich diese Ausgabe:
Looking up portsnap.FreeBSD.org mirrors... using portsnap2.FreeBSD.org.
Fetching snapshot tag... done.
Ports tree hasn't changed since last snapshot.
No updates needed.
Führe ich es jedoch über das subprocess Modul aus bekomme ich folgende Ausgabe:
portsnap fetch should not be run non-interactively.
Run portsnap cron instead.
Ich dachte shell=True würde dies überlisten, dem ist aber anscheinend nicht so. Es gibt bestimmt einen Weg die Programme glauben zu lassen sie würden in einer interaktiven shell laufen, oder?
Ich glaube wenn ich wirklich pty benutzten muss dann benutze ich pexpect welches auf pty aufbaut. Ich hatte mit pexpect angefangen, es aber durch subprocess ersetzt um so wenig wie möglich externe Abhängigkeiten zu haben.
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Ich dachte shell=True würde dies überlisten, dem ist aber anscheinend nicht so. Es gibt bestimmt einen Weg die Programme glauben zu lassen sie würden in einer interaktiven shell laufen, oder?
shell bedeutet nur dass eine Command-Shell gestartet wird um Deine Argumente zu behandeln. Unter Unix ist das zum Beispiel wichtig um Wildcards die Du an ein Programm mitgibst in einzelne Dateinamen aufzulösen; sowas macht nicht das Programm direkt (unter Windows schon, aber das ist eine ganz andere Geschichte).

Interaktive Shell zeichnet sich dadurch aus, dass sie an ein Terminal gebunden ist, und wenn eben die Programme eine interaktive Shell verlangen, dann bleibt Dir nix anderes übrig als Dich ans pty-Modul zu wenden, was ihnen ein echten Terminal vorspielt...
--- Heiko.
Antworten