Subprocess.Popen, eine Win32 Anwendung und "Argument"

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
handle
User
Beiträge: 4
Registriert: Donnerstag 11. August 2011, 12:08

Subprocess.Popen, eine Win32 Anwendung und ein Argument in Anführungszeichen unter Windows mit Python 3.2.

Code: Alles auswählen

try:
	retcode = subprocess.Popen( [ r"my.exe \"{}\"".format( "filename.ext" ) ], shell=True ).communicate()[0]
	print( retcode )
except WindowsError as e:
	print( e )
verursacht den Fehler "Das System kann den angegebenen Pfad nicht finden." Das ist das Verhalten der Anwendung, wenn der Dateiname nicht in Anführungszeichen übergeben wird (manuell).
Unter Windows verwendet Subprocess.Popen eine Methode, um eine Liste der Argumente in einen String umzuwandeln: print( subprocess.list2cmdline( params ) )
Das gibt etwas wie "my.exe \"filename.ext\""

Die Option shell=True bewirkt unterschiedliche Fehlermeldungen (ohne: "[Error 2] Das System...") der Anwendung, die eigentlich im Fehlerfall ein Dialogfenster öffnet. Vielleicht ist das das Problem, dass es sich nicht um eine echte Konsolenanwendung handelt?

PS: Wenn ich die Argumente als Liste übergebe, ohne shell=True, bewirkt das, dass der Fehler im Dialogfenster kommt.. Es bewirkt auch, dass list2cmdline keine Anführungszeichen um den kompletten Aufruf setzt, dafür ist aber das Argument, dass in Anführungszeichen sein sollte, mit Backslashes escaped (\"argument\") (In der Liste habe ich die Anführungszeichen manuell dem Argument-String hinzugefügt).
BlackJack

@handle: Das sieht so aus als hättest Du da wild herum probiert. Bei ``shell=True`` sollte man eine Zeichenkette übergeben mit genau der Zeichenkette, die man auch in der Eingabeaufforderung eingeben würde. So wie Du das geschrieben hast (mal die Liste ignorierend), wäre das ``my.exe \"filename.ext\"`` — was sicher nicht funktionieren dürfte wenn der Dateiname nicht tatsächlich mit Anführungsstrichen beginnt und endet.

Wenn Du nicht den Umweg über die Shell nimmst, was empfehlenswert ist, weil man sich dann nicht mit all dem herum schlagen muss, wovor man Werte in einer Kommandozeile schützen muss, dann müssen Programm und Argumente als einzelne Argumente in der Liste stehen! Weil man dann ja das aufteilen der Argumente selber macht, statt das der Shell zu überlassen. Das wäre dann einfach nur ``Popen(['my.exe', 'filename.ext'])``.
handle
User
Beiträge: 4
Registriert: Donnerstag 11. August 2011, 12:08

Hallo und Danke - ja, wenn es nicht funktioniert, muss ich ja probieren.
Als Liste scheint es besser zu funktionieren, aber die Ausgabe mit

Code: Alles auswählen

params = ["my.exe", '"file.name"']
print( subprocess.list2cmdline( params ) )
Führt zu

Code: Alles auswählen

my.exe \"file.name\"
und damit zu besagtem Dialogfenster der Anwendung mit der Fehlermeldung.

Wie bekomme ich die Backslashes weg?
handle
User
Beiträge: 4
Registriert: Donnerstag 11. August 2011, 12:08

So funktioniert es:

Code: Alles auswählen

retcode = subprocess.Popen( 'my.exe "file.name"', shell=True ).communicate()[0]
BlackJack

@handle: Die Backslashes sind da um die " for der Shell zu schützen. Wenn Du die " nicht haben willst, dann solltest Du *die* weglassen, statt etwas an den Folgen davon ändern zu wollen.
handle
User
Beiträge: 4
Registriert: Donnerstag 11. August 2011, 12:08

BlackJack hat geschrieben:Die Backslashes sind da um die " for der Shell zu schützen.
Der Mechanismus war mir nicht bekannt, aber trotzdem oder deswegen ging es leider nicht. Ich weiß nicht, was die Ursache ist, aber was ich erreichen wollte geht ja jetzt. Also Danke für deine Hilfe!
BlackJack

Die Ursache sind wie gesagt die " die *Du* hier reingeschrieben hast, die da nichts zu suchen haben wenn sie nicht tatsächlich Bestandteil des Dateinanmens sind:
handle hat geschrieben:

Code: Alles auswählen

params = ["my.exe", '"file.name"']
print( subprocess.list2cmdline( params ) )
Damit sagst Du das erste Argument für das Programm ist "file.name" was nicht stimmt, weil es tatsächlich nur file.name ist.
finki
User
Beiträge: 20
Registriert: Samstag 19. Februar 2011, 11:15

@handle
Was dir einige versuchen zu erklären ist, das wenn du subprocess eine Liste aller Argumente übergibst, dann brauchst du dir nicht die Mühe machen die Leerzeichen zu escapen. Das heißt praktisch keine Anführungszeichen um die Dateinamen schreiben. shell=True gibt an, das du keine Liste benutzen möchtest, sondern die Arbeit selbst in die Hand nimmst und ein String übergeben möchtest, als wenn du in der Kommandozeile sitzen würdest.

Wenn du allerdings eine Liste übergibst, ohne shell=True, dann übernimmt Python den Aufruf für dich und teilt die in der Liste stehenden Argumente auf und macht gegebenenfalls umgebende Anführungszeichen. So das nur mal als Verständnis. Eigentlich hat ja BlackJack das bereits erklärt.

Versuch es mal hiermit:

Code: Alles auswählen

try:
        cmdline = ['my.exe', 'filename.ext']
        retcode = subprocess.Popen(cmdline).communicate()[0]
        print( retcode )
except WindowsError as e:
        print( e )
Antworten