aufruf externer programme in python

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
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

kann mir jemand die unterschiedlichen methoden zusammenfassen?

ich kenne: subprocess, pexpect als module
popen intern, dazu ist fork() noch sinnvoll.

interessiert wär ich vor allem and den exec-varianten. execvp hab ich gefunden - es soll aber angeblich mehrere geben. weil ich in vielen fällen nicht einsehe dass eine instanz vom aufrufenden program weiterlaufen muss.

was ist der grund dafür dass diese methoden alle unterschiedlich mit argumenten umgehen?

ich will zum beispiel mit befehlen wie "/usr/bin/xterm -geometry 120x60 -e /usr/bin/powertop" umgehen können.
außer mit popen hab ich das noch mit keiner anderen geschafft. wieso? brauch ich dazu eine shell?
rückmeldungen zum python-programm sind eher nebensächlich, oder überhaupt in vielen fällen unerwünscht.

ich hab nicht viel programmiererfahrung und wär dankbar wenn jemand dieses mysterium für mich aufklären könnte.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

ichbinsisyphos hat geschrieben:was ist der grund dafür dass diese methoden alle unterschiedlich mit argumenten umgehen?
Weil das OS es so macht.
ichbinsisyphos hat geschrieben:ich will zum beispiel mit befehlen wie "/usr/bin/xterm -geometry 120x60 -e /usr/bin/powertop" umgehen können.
außer mit popen hab ich das noch mit keiner anderen geschafft. wieso? brauch ich dazu eine shell?
Also mit ``subprocess.Popen`` müsste das durchaus gehen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

Leonidas hat geschrieben:Weil das OS es so macht.
ja, gibts dazu noch mehr zu sagen? :-)
tut mir leid, ich würd gern spezifischer fragen, aber mir fehlt der background.
Leonidas hat geschrieben:Also mit ``subprocess.Popen`` müsste das durchaus gehen.
ja, möglich. ich hab subprocess zu beginn immer benutzt, weil ich die anderen nicht kannte. os.popen kenn ich erst seit letzter woche.

subprocess ist für meine zwecke auf grund des umgangs mit den argumenten im besten fall mühsam. ich glaub subprocess ist nur sinnvoll wenn man über das python script eine stärke kontrolle über den process will.


kennst du diese exec() varianten, von denen ich gelesen hab?

ist os.popen die einzige methode mit der ich den oben genannten befehl ohne zusätzlichen aufwand, umstellen von argumenten, etc., automatisiert ausführen lassen kann?


ach ja, spawn gibts da noch.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

ichbinsisyphos hat geschrieben:
Leonidas hat geschrieben:subprocess ist für meine zwecke auf grund des umgangs mit den argumenten im besten fall mühsam. ich glaub subprocess ist nur sinnvoll wenn man über das python script eine stärke kontrolle über den process will.
Beschreib doch einfach mal, was du machen willst, und warum du mit subprocess damit Probleme hast. Mit subprocess solltest du naemlich alles machen koennen, alle anderen popen-Funktion sollten damit ueberfluessig werden: http://docs.python.org/lib/node533.html
kennst du diese exec() varianten, von denen ich gelesen hab?
Ich bin zwar nicht Leonidas, aber die exec*-Funktionen sowie fork und spawn sind einfach nur sehr duenner wrapper um die C-API des Betriebssystems, ziemlich low-level, da sollte man als Python-Programmierer in der Regel einen Bogen drum machen. Wenn's dich trotzdem interessiert, solltest du mal ensprechende C-Doku lesen.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

ichbinsisyphos hat geschrieben:subprocess ist für meine zwecke auf grund des umgangs mit den argumenten im besten fall mühsam. ich glaub subprocess ist nur sinnvoll wenn man über das python script eine stärke kontrolle über den process will.
Wieso mühsam? Es vereinigt (fast) alle Methoden Prozesse aufzurufen unter einer konsistenten API.

Eben alle außer den hier dokumentierten - die sind aber weniger zum Aufrufen von Subprozessen da sondern zum Ersetzen des aktuellen Prozesses durch einen anderen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

Leonidas hat geschrieben:den hier dokumentierten
ja, genau, sowas hab ich gesucht, danke.


erm ... ich bein grad dabei ein script zu schreiben, dass ein menu für openbox erstellt.

in einem file hab ich program-name, programm- pfad inlusive aller argumente (siehe das beispiel mit xterm), kategorie und unterkategorie.

zusätzlich wird eine schnellstart-kategorie erstellt in der die programme nach der anzahl geordnet sind, in der die aufgerufen wurden.

die anzahl der aufrufe wird in einem anderen file mitgeschrieben. es sind also zwei dinge zu tun: programm starten und anzahl der aufrufe erhöhen.
im menu kann ich aber pro <execute>-tag nur einen befehl benutzen.

deswegen ist es das python-script, dass das programm das ich im menu wähle ausführt. es bekommt programm-name und -pfad als argumente, tut beides und erstellt ein neues menu.xml-file.

und das ist der grund, wieso ich an exec-funtionen interessiert bin, da bei jeder anderen methode für jedes programm das gestartet wird, eine instanz des scripts weiterlaufen muss, solange bis der unterprozess terminiert wird - falls ich das richtig verstehe.

os.popen gefällt mir im moment besser als subprocess.Popen, weil ich da den eintrag mit pfad und argumenten zur ausführung nicht ändern muss.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

ichbinsisyphos hat geschrieben:und das ist der grund, wieso ich an exec-funtionen interessiert bin, da bei jeder anderen methode für jedes programm das gestartet wird, eine instanz des scripts weiterlaufen muss, solange bis der unterprozess terminiert wird - falls ich das richtig verstehe.
Nein, Elternprozesse können terminieren. Der Sinn von exec* ist dass die PID gleich bleibt. Du kannst es dir etwa vorstellen, wie in einer Eizelle der Kern ausgetauscht wird. Aber ich sehe in deiner Erklärung keinen Grund warum du den Prozess ersetzen müsstest.

Beispiel:

Code: Alles auswählen

import subprocess
subprocess.Popen(['gedit'])
Startet gedit, beendet sich und derweil läuft gedit weiter.
ichbinsisyphos hat geschrieben:os.popen gefällt mir im moment besser als subprocess.Popen, weil ich da den eintrag mit pfad und argumenten zur ausführung nicht ändern muss.
Ähm, kannst du das mal an einem Stück Code demonstrieren, was du da meinst?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

scheint so, als ob subprocess die lösung für alle meine probleme ist.

wurde daran mal was geändert? ich hab grade in alten skripten gestöbert:

Code: Alles auswählen

subprocess.Popen("/usr/bin/setleds " "-L " "+num",shell=True)
da hab ich die argumente noch getrennt vom programm eingegeben (eingeben müssen?).

ein "bösartiger" eintrag in meiner liste wär zum beispiel:
  • #name:befehl:kategorie:unterkategorie
    rtorrent:/usr/bin/xterm -geometry 110x50 -e /usr/bin/rtorrent:Internet:Main
ich habs grad probiert und

Code: Alles auswählen

subprocess.Popen("/usr/bin/xterm -geometry 110x50 -e /usr/bin/rtorrent", shell=True)
funktioniert ohne probleme.

parent process wird sofort beendet, funktioniert wie gewünscht.

os.popen() hält das skript an an der stelle. da musste ich also forken, um überhaupt weiter zu kommen. und der geforkte prozess läuft solange bis das aufgerufene programm terminiert wird.

naja, dann danke für die hartnäckigkeit :-)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

ichbinsisyphos hat geschrieben:naja, dann danke für die hartnäckigkeit :-)
Dann bleib ich hartnächig: Du solltest als ersten Parameter eine Liste verwenden und die einzelnen Parameter als Listeneinträge, so wie in meinem Beispiel. Dann kannst du ``shell=True`` weglassen und musst dich nicht mehr um das Escapen von Leerzeichen etc kümmern.

PS: "ein " String" ist das gleiche wie "ein String", das wird also noch bevor die Funktion aufgerufen wird automatisch zusammengefügt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

Leonidas hat geschrieben:
ichbinsisyphos hat geschrieben:naja, dann danke für die hartnäckigkeit :-)
Dann bleib ich hartnächig: Du solltest als ersten Parameter eine Liste verwenden und die einzelnen Parameter als Listeneinträge, so wie in meinem Beispiel. Dann kannst du ``shell=True`` weglassen und musst dich nicht mehr um das Escapen von Leerzeichen etc kümmern.

PS: "ein " String" ist das gleiche wie "ein String", das wird also noch bevor die Funktion aufgerufen wird automatisch zusammengefügt.
was wär der vorteil? dazu müsst ich die einträge zerlegen, leerzeichen als delimiter, und in listen packen.


edit: so ungefähr:

Code: Alles auswählen

#!/usr/bin/env python

import subprocess

PROG="/usr/bin/xterm -geometry 100x20 -e /usr/bin/powertop"
LIST=PROG.split(" ")
#subprocess.Popen(PROG, shell = True)
subprocess.Popen(LIST)
ist es den zusätzlichen split-schritt wert?


zum PS: ist zu lange her um mich genau zu erinnern, aber ich habs damals nicht geschafft es anders zum laufen zu bringen. den ganzen string unter ein einziges paar von anführungszeichen zu setzen wär ja das naheliegendste.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Wens schon für die Shell gequotet ist dann macht das keinen Sinn mehr - wie würde deine Datei aussehen, wenn man als Parameter eine Datei mit Leerzeichen angeben wollte?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

1. leicht zu vermeiden.
2. auf die alte art gehts. sowohl mit anführungszeichen als auch backslash-escape.

in liste umwandeln geht dann aber nicht mehr so einfach.

die befehle kommen aus einer datei die so aussieht:

Code: Alles auswählen

...
KWord:/usr/bin/kword:Office:KOffice
LatencyTop:/usr/bin/xterm -e sudo /usr/sbin/latencytop:System:Main
Lyx:/usr/bin/lyx:Office:Main
#Mplayer:/usr/bin/gmplayer:Multimedia:Main
#ncmpc:/usr/bin/xterm -e /usr/bin/ncmpc:Multimedia:Main
Pidgin:/usr/bin/pidgin:Internet:Main
PowerTop:/usr/bin/xterm -e sudo /usr/bin/powertop:System:Main
Python:/usr/bin/xterm -e /usr/bin/python:Shells:Main
rtorrent:/usr/bin/xterm -geometry 110x50 -e /usr/bin/rtorrent:Internet:Main
...
die datei wird mit readlines() eingelesen und an den doppelpunkten geteilt

Code: Alles auswählen

test:"test test.py":Misc:Main
und

Code: Alles auswählen

test:test\ test.py:Misc:Main
funktioniert.

ich weiß aber nicht, worauf du hinaus willst.
lunar

Hältst du dieses Format wirklich für intelligent? Es gibt nämlich auch Programme wie imagemagick, die Doppelpunkte in Argumenten erfordern. Ein "str.split" an Doppelpunkten würde hier die Argumentliste erhacken.

Ini-Dateien wäre da besser geeignet:

Code: Alles auswählen

[KWord]
command=/usr/bin/kword
categories=Office:KOffice
Damit kann das Kommando sauber ausgelesen werden.

Subprocess mit einer Argumentliste ist nur dann sinnvoll, wenn man Nutzereingaben als Teil eines externen Kommandos einsetzen möchte. Als Beispielt dient auch hier wieder imagemagick. Nehmen wir an, du möchtest eine kleine Oberfläche für import schreiben, um dem Nutzer die graphische Auswahl des Zieldateinamens zu ermöglichen. Dazu müsstest du den Dateinamen sicher an import übergeben, ohne das Leerzeichen oder andere Sonderzeichen der Shell Probleme machen. Der Aufruf mit shell=False und einer Liste als Argument vermeidet hier alle Kopfschmerzen zwecks Shell-Quoting.

Wenn du aber dem Nutzer die Möglichkeit geben möchtest, vollständige Kommandos auszuführen, dann ist das nur ein unnötiger Umweg.
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

aso, verstehe.

also der einzige benutzer bin ich selbst. und ich kann mir beim besten willen nicht vorstellen, dass ich mal einen befehl der ":" im syntax benutzt ins openbox menu schreibe.
und wenns mal passiert, dann lass ich mir was einfallen.

mir ist aber wichtig, dass die einträge kurz und effizient sind und alles in eine zeile passt. wenn die datei komplizierter wird, dann kann ich gleich wieder xml-dateien schreiben :P
BlackJack

"Das werde ich sowieso nie brauchen…" oder "Das benutze ich nur selbst…" sind so Sätze die einem manchmal zu den unpassendsten Momenten lügen strafen. ;-)

Wie wär's mit CSV als Datenformat? Einfach, aber man kann trotzdem alles eintragen, weil sich das Trennzeichen "escapen" lässt.
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

BlackJack hat geschrieben:"Das werde ich sowieso nie brauchen…" oder "Das benutze ich nur selbst…" sind so Sätze die einem manchmal zu den unpassendsten Momenten lügen strafen. ;-)

Wie wär's mit CSV als Datenformat? Einfach, aber man kann trotzdem alles eintragen, weil sich das Trennzeichen "escapen" lässt.
du meinst beistrich statt doppelpunkt als trennzeichen? oder impliziert "CSV datenformat" mehr?

also darüber können wir auf alle fälle reden ;-)
kommt aber wahrscheinlich ziemlich aufs selbe raus.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

ichbinsisyphos hat geschrieben:
BlackJack hat geschrieben:"Das werde ich sowieso nie brauchen…" oder "Das benutze ich nur selbst…" sind so Sätze die einem manchmal zu den unpassendsten Momenten lügen strafen. ;-)

Wie wär's mit CSV als Datenformat? Einfach, aber man kann trotzdem alles eintragen, weil sich das Trennzeichen "escapen" lässt.
du meinst beistrich statt doppelpunkt als trennzeichen? oder impliziert "CSV datenformat" mehr?
Weder mehr noch weniger sondern was anderes. CSV heißt eigentlich dass es in Spalten aufgeteilt ist, aber es müssen nicht kommas als begrenzer sein, Tabs und eigentlich jedes andere Zeichen geht auch (ein Kumpel von mir argumentiert immer das Tab-CSV kein CSV ist, aber das kommt mir arg formal vor, denn bis auf das Trennzeichen verhält sich Tabbed-CSV genauso wie normales Komma-CSV). In CSV hast du aber die Möglichkeit Dinge zu Quoten etwa ``Val1,"Vorname,Nachname",Val2``. was drei und nicht vier Spalten entsprechen würde.

Ich finde an dieser Stelle nicht einmal XML so verkehrt. Da fällt mir Lunabox ein, ein Fork von Openbox der Lua einsetzt um die XML-Konfiguration durch Lua zu ersetzen - wer's braucht.
Zuletzt geändert von Leonidas am Mittwoch 2. Juli 2008, 13:36, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

Was als Trennzeichen genommen wird ist egal, wichtig ist, dass das Trennzeichen selbst trotzdem in den Daten vorkommen kann. Schau Dir einfach mal das `csv`-Modul an.
ichbinsisyphos
User
Beiträge: 120
Registriert: Montag 4. Juni 2007, 19:19

aso, python hat da einen eingebauten parser. ja, werd ich mir anschauen, guter tip.
Leonidas hat geschrieben:Ich finde an dieser Stelle nicht einmal XML so verkehrt.
ich find xml verkehrt von der user-perspektive aus. ich weiss schon, wieso xml gern für config dateien benutzt wird, aber das mit der hand einzugeben ist zu mühsam für den täglichen gebrauch wenn man regelmässig was ändert.

das skript ist für mich nur ein vorwand mich in der freien zeit mit python auseinander zu setzen, das schnellstart-menu ist nur eingeschränkt sinnvoll.
der einzig gute grund wieso ich das skript trotzdem immer noch tagtäglich benutze ist, dass ich neue menü-einträge mit minimalem aufwand machen kann.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

ichbinsisyphos hat geschrieben:ich weiss schon, wieso xml gern für config dateien benutzt wird, aber das mit der hand einzugeben ist zu mühsam für den täglichen gebrauch wenn man regelmässig was ändert.
Nicht dass es kompliziert wäre dafür eine Oberfläche zu machen oder so...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten