os.system Rückgabewert Problem

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
Chrispy
User
Beiträge: 37
Registriert: Montag 10. September 2007, 22:43

Da der Standard GNOME Run Dialog keine Variablen akzeptiert habe ich mich entschlossen einfach selber einen in PyGTK zu schreiben, bis auf den Rückgabewert von os.system klappt das ja auch wunderbar.

Den Wert hole ich mir wie folgt:

self.execute = os.system("was weiss ich")
self.signal = self.execute & 0xFF
self.exitcode = (self.signal >> 8 ) & 0xFF

Direkt im Python Interpreter _kein_ Problem, aber im Script funktioniert das nicht...

Hier noch die ganze Funktion zur Programmausführung ...

Code: Alles auswählen

def run(self, command):
                self.infolabel.set_text("")
                if self.terminal_checkbox.get_active() and self.root_checkbox.get_active():
                        self.command = "gksu -u root \"%s -e `bash -c \'%s\'`\"" % (self.terminal, self.entry_command.get_text())
                        self.execute = os.system("%s &" % self.command)
                elif self.terminal_checkbox.get_active() and self.root_checkbox.get_active() != True:
                        self.command = "%s -e \"bash -c \'%s\'\"" % (self.terminal, self.entry_command.get_text())
                        self.execute = os.system("%s &" % self.command)
                elif self.terminal_checkbox.get_active() != True and self.root_checkbox.get_active():
                        self.command = "gksu -u root %s" % self.entry_command.get_text()
                        self.execute = os.system('%s &' % self.command)
                else:
                        self.command = "%s" % (self.entry_command.get_text())
                        self.execute = os.system("%s &" % self.command)
                self.signal = self.execute & 0xFF
                self.exitcode = (self.signal >> 8) & 0xFF
                print "%s" % self.exitcode
                if self.exitcode == 127:
                        self.infolabel.set_text(_("Command not found"))
                elif self.exitcode != 0:
                        print "Something went wrong"
                        self.infolabel.set_text(_("Something went wrong"))
                else:
                        if self.command not in self.history:
                                self.history.append(self.command)
                                self.history_list.append_text(self.command)
                                gconf_database.set_list("/apps/gnome-settings/gnome-panel/history-gnome-run", "string", self.history)
                        gtk.main_quit()
Ich hoffe jemand hat ne Antwort parat.
lunar

Anstatt magisch Bytes rumzuschieben, könntest du auch einfach ``os.WEXITSTATUS``, ``os.WTERMSIG`` und ``os.WIFSIGNALED`` nutzen.

Ferner solltest du dich fragen, ob die Shell Injection wirklich beabsichtigt ist, oder ob du zumindest deine Quoting-Logik nicht dahingehen verbessern möchtest, dass Werte mit Hochkommata korrekt gequotet werden.

Zuguterletzt wäre eine etwas ausführlichere Fehlerbeschreibung als "funktioniert nicht" hilfreich ;)
Chrispy
User
Beiträge: 37
Registriert: Montag 10. September 2007, 22:43

Zuguterletzt wäre eine etwas ausführlichere Fehlerbeschreibung als "funktioniert nicht" hilfreich Wink
Äh ja. Das Ergebnis ist im Interpreter immer korrekt (0 oder 1 oder 127 usw.) im Script ist es immer 0 (auch dann wenn es 1 oder 127 wäre)
oder ob du zumindest deine Quoting-Logik nicht dahingehen verbessern möchtest, dass Werte mit Hochkommata korrekt gequotet werden.
Gut, aber wie? Python will die Dinge Gequotet haben, gnome-terminal und gksu auch nochmal extra. Dies hier war die bis dato einzige funktionierende Lösung es allen dreien Recht zu machen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Man könnte ja subprocess.Popen nutzen, dann hat sich das Quoten auch erledigt. Ich denke lunar wollte auf genau das anspielen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Chrispy
User
Beiträge: 37
Registriert: Montag 10. September 2007, 22:43

Hmm. Zumindest das mit dem Rückgabewert funktioniert jetzt einwandfrei. :freu:

Mal sehen ob ich das mit gksu und gnome-terminal auch noch hinbekomme.
lunar

Chrispy hat geschrieben:Gut, aber wie?
Tja, das ist eine gute Frage, die schon so Manchem Kopfschmerzen bereitet hat. Deswegen vermeidet man ja die Shell auch soweit als möglich, und nutzt lieber ``subprocess.Popen``, sofern man nicht unbedingt auf die Shell angewiesen ist.

Dein Problem ist, dass ``os.system`` immer den Exitcode von ``/bin/sh`` zurückgibt. Für den Fall, dass das aufgerufene Skript in der Shell terminiert, gibt ``/bin/sh`` den Exitcode des letzten Kommandos zurück.

Du allerdings schiebst den Prozess mit ``&`` in den Hintergrund. Das führt dazu, dass die Shell eine neue Subshell forkt, die SIGHUP ignoriert, und das Kommando ausführt. Danach beendet sich die Shell. Die geforkte Subshell lebt zu diesem Zeitpunkt noch, ergo kann die Shell deren Rückgabewert nicht abfragen. Folglich gibt sie ihren eigenen zurück, und da beim Forken der Subshell nun mal kein Fehler auftrat, ist der Statuscode immer 0.

Ähnliches gilt wohl bei der Ausführung über ``gksu`` und ``gnome-terminal``.

Gratulation, du gehörst zur langen Reihe von Programmierern, die über Tücken von ``os.system`` und ``/bin/sh`` gestolpert sind ;)
Chrispy
User
Beiträge: 37
Registriert: Montag 10. September 2007, 22:43

Gratulation
Danke. Danke. Danke.

Ich hab zu gksu + subprocess noch ne Frage

self.command ist in dem Fall:

Code: Alles auswählen

nautilus $HOME --no-desktop

Code: Alles auswählen

self.execute = subprocess.call(["gksu -u root" + self.command], shell=True)
das shell equivalent wäre dieses:

Code: Alles auswählen

gksu -u root nautilus $HOME --no-desktop
Hier liegt mein Problem: es müsste eigentlich:

Code: Alles auswählen

gksu -u root "nautilus $HOME --no-desktop" 
sein, da --no-desktop sonst von gksu als eigene option interpretiert wird ... Rat?
Chrispy
User
Beiträge: 37
Registriert: Montag 10. September 2007, 22:43

ok. hat sich erledigt.

Ich würd halt mal:

Code: Alles auswählen

self.execute = subprocess.call(["gksu -u root" + "\"" + self.command + "\"" ], shell=True)
Manchmal sind die Knoten im Hirn wirklich groß ...
lunar

Dir ist doch klar, dass du so zwar das Problem der Rückgabe gelöst hast, aber noch nicht das Problem des Quotings?
Chrispy
User
Beiträge: 37
Registriert: Montag 10. September 2007, 22:43

Richtig. Aber wie gesagt: Ich habe keine Ahnung. Und es ist das erste mal, dass ich subprocess benutze.
lunar

Wie wäre es mit

Code: Alles auswählen

self.process = subprocess.call(['gksu', '-u', 'root', self.command])
Chrispy
User
Beiträge: 37
Registriert: Montag 10. September 2007, 22:43

perfekt.

Noch ne Frage: Eigentlich sollte ein Run Dialog sich ja schliessen, wenn das Programm erfolgreich gestartet wurde, tut er aber nicht. ( dafür war das & am ende des kommandos gedacht, dieses verhindert aber die korrekte Rückgabewert Angabe).
Antworten