Subprocess 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
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Hallo Freunde,

ich habe ein großes/kleines (Größen sind relativ) Python Problem.
Meine Ausgangssituation ist wiefolgt, ich möchte ein Ausführbare Datei unter Linux starten.
Diese befindet sich im Verzeichnis /home/rentd/services/vt2/127.0.0.1/3801 und trägt den Namen "ventrilo_svr".

Hier für nutze ich dann folgenden String/Befehl, um diese Auszuführen:
/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_svr
Anbei jedoch, benötige ich einen Parameter: "-f/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_svr"

Der komplette Zeile lautet dementsprechend:
/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_svr -f/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_svr
Wenn ich diese Zeile 1:1 in meiner /bin/bash ausführe, funktioniert es problemlos! Der Server startet korrekt und findet mit -f seine korrekten Pfade.
Auch wenn ich diese Zeile 1:1 in mein Pythonscript einbinde (siehe Quellcode), funktioniert es.

Nun ist es so, dass die IP/Port Variablen sind.. also ersetze ich diese durch meine eigenen Vars um das Python-Programm dynamisch zu machen.

Der IP und Port erhalte ich aus der Variable l_s[4] und ls_s[5] (Tuple-Typ). Wenn ich mir diese auf die Konsole printen lasse, ist auch alles korrekt. Auch die auszuführende Zeile, welche damit erstellt wird, wird korrekt dargestellt und erzeugt. Denn wenn ich diese Zeile selbst kopiere und einfüge in meiner Shell, startet der Serverdienst erfolgreich.

Quellcode (Server startet nicht korrekt):

Code: Alles auswählen

import subprocess

ExecuteLine = "/home/rentd/services/vt2/%s/%s/ventrilo_srv -f/home/rentd/services/vt2/%s/%s/ventrilo_srv" % (str(l_s[4]),str(l_s[5]),str(l_s[4]),str(l_s[5]))
# l_s[4] = 127.0.0.1
# l_s[5] = 3801

print "ExecuteLine: "+ExecuteLine
# print Ausgabe = "/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_srv -f/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_srv"

proc = subprocess.Popen([ExecuteLine], shell=True, executable='/bin/bash')
Der Dienst startet mit der Meldung:
Ventrilo Server - Version 2.1.2
(c)Copyright 1999-2003 Flagship Industries, Inc.

Server must have a valid name.
ERROR: Unable to read configuration data. Exiting
Nun starte ich den Dienst selbst, über die Ausgegeben Printzeile.
Ventrilo Server - Version 2.1.2
(c)Copyright 1999-2003 Flagship Industries, Inc.

20090914 12:31:55 Version = 2.1.2
20090914 12:31:55 Name = test123
Es funktioniert.

Aus Spaß habe ich diese Zeile 1:1 in meinen Pythonquellcode eingebaut.

Quellcode (Server startet, statischer Code):

Code: Alles auswählen

import subprocess

ExecuteLine = "/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_srv -f/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_srv"
# l_s[4] = 127.0.0.1
# l_s[5] = 3801

print "ExecuteLine: "+ExecuteLine
# print Ausgabe = "/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_srv -f/home/rentd/services/vt2/127.0.0.1/3801/ventrilo_srv"

proc = subprocess.Popen([ExecuteLine], shell=True, executable='/bin/bash')
Der Code funktioniert. Das Problem besteht also dahin, dass wenn ich meine Variablen dort einsetze. Das Subprocess irgendwas falsch macht!
Ich bin mittlerweile am Ende. Vielleicht weiss einer von euch Rat. Umwandlung der Variablen mit str() bracht auch nichts.[/quote]
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Nicht so:

Code: Alles auswählen

subprocess.Popen(["ls -l"])
Sondern so:

Code: Alles auswählen

subprocess.Popen(["ls", "-l"])
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Leider bringt dies auch nichts.

Hier der Quellcode:

Code: Alles auswählen

ExecuteLine_S = path+"ventrilo_srv "
ExecuteLine_P = "-f"+path+"ventrilo_srv"

# ExecuteLine_S = /home/rentd/services/vt2/195.13.63.151/3804/ventrilo_srv
# ExecuteLine_P = -f/home/rentd/services/vt2/195.13.63.151/3804/ventrilo_srv

proc = subprocess.Popen([ExecuteLine_S,ExecuteLine_P], shell=True, executable='/bin/bash')
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Für das Zusammensetzen von Pfaden gibt es os.join()!

Das hier sieht krude aus:

Code: Alles auswählen

ExecuteLine_P = "-f"+path+"ventrilo_srv"
Das "-f" ist doch ein Parameter! Wieso joinst Du den mit dem zugehörigen Wert? Du sollst diese Sachen ja gerade als Liste übergeben!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Versuchs mal so:

Code: Alles auswählen

ExecuteLine_S = os.path.join(path, "ventrilo_srv")
ExecuteLine_P = "-f" + ExecuteLine_S

proc = subprocess.Popen([ExecuteLine_S, ExecuteLine_P])
(Das ganze ``shell=True``-Zeug ist total unnütz)

@Hyperion: einige Programme nehmen ihre Paramter im Format -fWERT und nicht -f WERT entgegen, von daher kann das durchaus richtig sein. Auch wenn diese Art Parameter zu übergeben ziemlich blödsinnig ist, aber da ist schon das aufzurufende Programm schuld.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Leonidas hat geschrieben: @Hyperion: einige Programme nehmen ihre Paramter im Format -fWERT und nicht -f WERT entgegen, von daher kann das durchaus richtig sein. Auch wenn diese Art Parameter zu übergeben ziemlich blödsinnig ist, aber da ist schon das aufzurufende Programm schuld.
Hui, jetzt wo Dus sagst, stimmt. Ist mir irgend wann auch schon mal über den Weg gelaufen.
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Leonidas hat geschrieben:Versuchs mal so:

Code: Alles auswählen

ExecuteLine_S = os.path.join(path, "ventrilo_srv")
ExecuteLine_P = "-f" + ExecuteLine_S

proc = subprocess.Popen([ExecuteLine_S, ExecuteLine_P])
(Das ganze ``shell=True``-Zeug ist total unnütz)

@Hyperion: einige Programme nehmen ihre Paramter im Format -fWERT und nicht -f WERT entgegen, von daher kann das durchaus richtig sein. Auch wenn diese Art Parameter zu übergeben ziemlich blödsinnig ist, aber da ist schon das aufzurufende Programm schuld.
Leider ebenfalls ohne Erfolg, das Programm gibt die typische "read error" Fehlermeldung.
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Ich habe mal die Software hochgeladen, damit man das Problem selbst rekonstruieren könnte.

http://195.13.63.151/freiheit/vt2.tar.gz

Läuft unter x86-Architektur.

Habe das Programm in folgender Ordnerstruktur:
/home/rentd/services/vt2/127.0.0.1/3801/
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Darf man Threadpushing betreiben? :P
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Habe festgestellt, dass es 1x mal funktioniert. Wenn ich jedoch einen zweiten Server starte, taucht das Problem wieder auf. Erst nach einem kompletten Neustart des Hardwareservers kann ich wieder das Script 1x erfolgreich ausführen, beim zweiten, dritten Start usw. funktioniert es wieder nicht.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

"Geht nicht " ist die berühmte Nichtfehlermeldung :roll:
Gibt das Programm irgendwas aus (Wahrscheinlich auf stderr)?

"Server" klingt, als wären da evtl. noch ports/sockets belegt/übrig etc.
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Als Fehlermeldung gibt es folgende Meldung:

Code: Alles auswählen

Ventrilo Server - Version 2.1.2
(c)Copyright 1999-2003 Flagship Industries, Inc.

Server must have a valid name.
ERROR: Unable to read configuration data. Exiting.
BlackJack

@Temoc: Und wo und wie übergibst Du den Servernamen?
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Hallo,

ich konnte das Problem lösen. Es lag am vorherigen ConfigParser von Python, welchen ich nun durch ConfigObj ersetzt habe.

Habe euch mal beide Varianten bereitgestellt, ggf. findet jmd den Fehler durch eine tiefergehende Analyse...

Code: Alles auswählen

------------------------------------------------
--- DIE FOLGENDE VARIANTE FUNKTIONIERT NICHT ---
------------------------------------------------

vtc = ConfigParser.RawConfigParser()
cfgfile = open("ventrilo_srv.ini","w")
vtc.add_section('Server')
vtc.set('Server','Comment','- Ventrilo 2.1 Server')
vtc.set('Server','Port',"3801")
vtc.set('Server','AdminPassword','geheim')
vtc.set('Server','Password',"geheim")
vtc.set('Server','MaxClients',"8")
vtc.set('Server','Auth','1')
vtc.set('Server','Duplicates','0')
vtc.set('Server','SendBuffer','0')
vtc.set('Server','RecvBuffer','0')
vtc.set('Server','Diag','0')
vtc.set('Server','LogonTimeout','5')
vtc.set('Server','CloseStd','1')
vtc.set('Server','FilterWave','0')
vtc.set('Server','FilterTTS','0')
vtc.set('Server','TimeStamp','1')
vtc.set('Server','PingRate','10')
vtc.set('Server','ExtraBuffer','0')
vtc.set('Server','ChanWidth','0')
vtc.set('Server','ChanDepth','0')
vtc.set('Server','ChanClients','0')
vtc.set('Server','DisableQuit','1')
vtc.set('Server','VoiceCodec','0')
vtc.set('Server','VoiceFormat','3')
vtc.set('Server','SilentLobby','0')
vtc.set('Server','Name',"Servername")
vtc.add_section('Status')
vtc.set('Status','Intf',"10.10.10.10")
vtc.add_section('Intf')
vtc.set('Intf','Intf',"10.10.10.10")
vtc.write(cfgfile)

------------------------------------------
--- DIE FOLGENDE VARIANTE FUNKTIONIERT ---
------------------------------------------

config = ConfigObj()
config.filename = "ventrilo_srv.ini"

section1 = {
	'Intf': '10.10.10.10',
}
config['Intf'] = section1
config['Status'] = section1
section2 = {
	'Comment': '- Ventrilo 2.1 Server',
	'Port': '3801',
	'AdminPassword': 'geheim',
	'Password': 'geheim',
	'MaxClients': '8',
	'Auth': '1',
	'Duplicates': '0',
	'SendBuffer': '0',
	'RecvBuffer': '0',
	'Diag': '0',
	'LogonTimeout': '5',
	'CloseStd': '1',
	'FilterWave': '0',
	'FilterTTS': '0',
	'TimeStamp': '1',
	'PingRate': '10',
	'ExtraBuffer': '0',
	'ChanWidth': '0',
	'ChanDepth': '0',
	'ChanClients': '0',
	'DisableQuit': '1',
	'VoiceCodec': '0',
	'VoiceFormat': '3',
	'SilentLobby': '0',
	'Name': "Servername",
}
config['Server'] = section2
config.write()
lunar

Die erste Variante kann auch allenfalls durch einen glücklichen Zufalls funktionieren. Die Konfigurationsdatei, welche Du zum Schreiben geöffnet hast, wird nie geschlossen. Daher verbleiben die geschriebenen Daten im Puffer der E/A-Schicht, der gestartete Dienst sieht immer nur eine leere Datei.

Merke: Dateien immer korrekt schließen. Am besten verwendest Du zur Arbeit mit Dateien oder allgemein jeder Art von Ressource die "with"-Anweisung. Mehr dazu steht in der Dokumentation.
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Wie kann ich denn die Datei korrekt schließen, magst es mir verraten? :-)
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

In dem man sie schließt, mit .close() oder mit "with"

Code: Alles auswählen

with open('my_file.txt', 'w') as f:
    f.write('asd')
# hier gehts weiter
the more they change the more they stay the same
lunar

@Temoc: Nun, Du kannst auch einfach die Dokumentation lesen ...
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

lunar hat geschrieben:@Temoc: Nun, Du kannst auch einfach die Dokumentation lesen ...
http://docs.python.org/tutorial/inputou ... ting-files
Temoc
User
Beiträge: 15
Registriert: Montag 14. September 2009, 11:19

Wär ja nicht so, als würde ich nicht den halben Tag davor sitzen... aber dennoch danke für eure Hilfe.
Antworten