Mit subprocess.call xterm starten und parent schließen

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.
BlackJack

@mutetella: Was ist denn für Dich ”der Launcher”? Worauf willst Du überhaupt warten? Nach einem `Popen()` ist das Programm gestartet, da musst Du nicht drauf warten.

Die Prozesse ”senden” auch kein `None`. Was Du mit `poll()` abfragst ist der Rückgabecode des Prozesses. Und solange der noch läuft bekommst Du halt `None` von diesem Aufruf zurück weil es noch keinen Rückgabecode gibt, denn der steht ja erst am Ende des Prozesses fest. Wenn Du von `poll()` etwas anderes als `None` zurück bekommst dann gibt es den Prozess nicht mehr. Es macht also auch keinen Sinn danach noch weiter `poll()` aufzurufen, weil das natürlich immer den selben Wert liefert, eben den Rückgabecode den der Prozess am Ende per `exit()` an das Betriebssystem zurückgegeben hat.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@mutetella:
Die exec*-Calls geben Dir überhaupt nie was zurück, wie auch - exec ersetzt den aktuellen Prozess mit dem neuen, d.h. alles was nach exec* in Deinem Skript kommt, wird nie erreicht.

Warum muss die Auswahl eigentlich in einem neuem Terminal laufen und das alte geschlossen werden? Warum nicht einfach im selben Terminal bleiben? Da kannst Du prima mit exec Prozesshopping betreiben.

Wie stellst Du überhaupt sicher, dass das Terminal mit Skriptende auch mit geschlossen wird? Zwar verhalten sich die meisten Emulatoren unter X so, das OSX Terminal z.B. aber nicht - dort bleibt das Terminalfenster mit einer letzten Statusmeldung offen. Um hier sicher zu gehen, müsstest Du das Terminal selbst abschiessen.

@BlackJack:
In mutetellas Ansinnen müsste man tatsächlich mindestens solange warten, bis der Subprozess sich detached hat, um nicht als noch Kindprozess mit dem Terminal mit beendet zu werden.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@mutetella: so langsam verstehe ich, was Du zu erreichen versuchst.
Du startest Deinen Launcher über `xterm -e launcher`. Dann willst Du eine Auswahl treffen, ein neues Programm soll gestartet werden und das alte xterm-Fenster geschlossen werden. Dazu mußt Du wissen, dass alle Kinder und Kindeskinder eines Prozesses das Signal SIGHUP gesendet bekommen, wenn ein xterm-Fenster geschlossen wird. Das beendet normalerweise den Prozess, außer man ignoriert das Signal.

Code: Alles auswählen

import os
import signal

items = [
    ('ranger', ('xterm', '-e', 'ranger')),
    ('iceweasel', ('iceweasel',))
]
 
def start():
    for idx, item in enumerate(items):
        print '{:2d} {}'.format(idx, item[0])
    choice = int(raw_input('> '))
    app = items[choice][1]
    signal.signal(signal.SIGHUP, signal.SIG_IGN)
    pid = os.fork()
    if pid == 0:
        os.execvp(app[0], app)
 
if __name__ == '__main__':
    start()
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Die Prozesse ”senden” auch kein `None`. Was Du mit `poll()` abfragst ist der Rückgabecode des Prozesses.
Das ist mir schon klar. Nur ist es halt so, dass der Kindprozess erst gar nicht zum Starten kommt, wenn der Elternprozess zu früh beendet wird. Wenn ich also ohne zeitliche Verzögerung ``p = subprocess.Popen(wasauchimmer); sys.exit()`` mache, dann startet `wasauchimmer` erst gar nicht, weil der Elternprozess zuvor schon wieder geschlossen wird. Ich dachte eben, dass es evtl. eine Möglichkeit gibt, `p` abzufragen, ob das zugrundeliegende Programm bereits gestartet ist.
jerch hat geschrieben:Warum muss die Auswahl eigentlich in einem neuem Terminal laufen und das alte geschlossen werden?
Ich verwende i3 als Fenstermanager. Das Launcherskript möchte ich in einem floating window starten, die daraus gestarteten Programme aber nicht.
jerch hat geschrieben:Wie stellst Du überhaupt sicher, dass das Terminal mit Skriptende auch mit geschlossen wird?
Den Job übernimmt X für mich. Und OSX interessiert mich nicht... :wink:

@Sirius3
Sind meine Kommentare richtig?

Code: Alles auswählen

    # if SIGHUP occurs, ignore it
    signal.signal(signal.SIGHUP, signal.SIG_IGN)
    # create new child process
    pid = os.fork()
    # start app within child if creation not fails
    if pid == 0:
        os.execvp(app[0], app)
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Der ' if creation not fails'-Zusatz ist falsch. Ob die Erzeugung geklappt hat wird da nicht geprüft, sondern in welchem der beiden Prozesse man sich befindet.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Um der Sache auf die Schliche zu kommen, hier mal eine quick&dirty Funktion dazu:

Code: Alles auswählen

def print_processpath(pid):
    while pid:
        print os.popen('ps -p %d -opid=,command=' % pid).read().strip(), os.getsid(pid) == pid
        pid = int(os.popen('ps -p %d -oppid=' % pid).read().strip())
Ruft man diese mit `print_processpath(os.getpid())` auf, so sieht man die Elternprozesse (PID und Command) bis zum Root-Prozess (init). Das Flag dahinter zeigt an, ob ein Prozess session leader ist. Was es alles damit auf sich hat - siehe http://ftp.gnu.org/old-gnu/Manuals/glib ... bc_27.html

Ruft man das in einem xterm mit Shell in ipython auf, sieht es so aus:

Code: Alles auswählen

In [5]: print_processpath(os.getpid())
13689 /usr/bin/python /usr/bin/ipython False
13441 bash True
13439 /usr/bin/xterm False
4187 init --user True
4161 lightdm --session-child 12 25 False
1188 lightdm True
1 /sbin/init True
in 'xterm ipython' dagegen:

Code: Alles auswählen

In [3]: print_processpath(os.getpid())
13769 /usr/bin/python /usr/bin/ipython True
13767 xterm ipython False
13441 bash True
13439 /usr/bin/xterm False
4187 init --user True
4161 lightdm --session-child 12 25 False
1188 lightdm True
1 /sbin/init True
xterm verhält sich nun so, dass es sich beendet, wenn der erste session leader am pty-slave stirbt (dabei wird das SIGHUP an alle Kinder ausgelöst). Alternativ könnte man auch xterm direkt beenden, was der Urbedeutung des SIGHUP (Gegenstelle des Terminals hat aufgelegt) gleich kommt und immer dann passiert, wenn man den Schliessen-Button des Fenstermanagers drückt.
Antworten