Subprocess öffnet Konsolenfenster

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.
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Hallo,

ich starte mit subprocess.popen(...) einen neuen Prozess und lese dann dessen Ausgabe. Klappt auch wunderbar, nur öffnet sich bei einem Kollegen jedesmal ein Konsolenfesnter(cmd.exe), welches sich auch gleich wieder schließt (Prozess zu Ende). Bei mir zeigt sich dieses Verhalten nicht, obwohl ich ebenfalls WindowsXP-SP2 am Laufen habe. Python-Version ist dieselbe.

Ist ein bisschen nervig, da ich mit xcopy mehrere Dateien kopiere und entsprechend oft ein neuer Prozess gestartet wird.
Wie kann ich das "aufpoppen" der Konsole verhindern?


Hier der Code:

Code: Alles auswählen

	def runProcess(self, cmd, name):
		try: 
			exec_dir = os.getcwd()
			if verboseFlg:
				if gui == True:
					# self.printer("opening process %s" % " ".join(cmd), self.tabNum, myout['std'])
					p = Popen(cmd, bufsize=1, cwd=exec_dir, stderr=subprocess.STDOUT, stdout=PIPE) #redirect stderr to stdout and stdout to pipe
					# self.printer("process opened", self.tabNum, myout['std'])
					
					#reading from pipe
					with p.stdout as f:
						# self.printer("reading to buffer", self.tabNum, myout['info'])
						read_data = f.read() # read() blocks until buffer is full or subprocess returns
						self.printer(read_data, self.tabNum, myout['ext'])
					f.closed
					# self.printer("process closed", self.tabNum, myout['std'])
					
				else:
					subprocess.check_call(cmd, bufsize=1, cwd=exec_dir)
			else:
				fnull = open(os.devnull, "w")
				subprocess.check_call(cmd, bufsize=1, cwd=exec_dir, stderr=fnull, stdout=fnull)
				fnull.close()
		except subprocess.CalledProcessError,e:
			self.printer("%s failed" % name, self.tabNum, myout['err'])
		else:
			# self.printer("%s finished" % name, self.tabNum, myout['std'])
			pass
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Nutzt der Kollege denn das exakt gleiche Python-Script?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Und fairerweise muss man sich auch fragen warum du ``xcopy`` verwendest, wenn Python doch auch Dateien kopieren kann.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Ja, er nutzt exakt das gleiche Script!

Ja, Python kann zwar auch Dateien kopieren ist aber ziemlich aufwendig wenn man ganze Ordner mit Inhalt in andere Ordner kopieren will (Zielverzeichnis muss laut shutil leer sein, Ordner werden nicht automatisch erstellt). Ich will dies aber nicht zum Topic machen, da die runProcess(..) Methode noch weitere Programme ausführt und immer ein Konsolenfenster aufpoppt.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Startet ihr das Script auch gleich, oder nutzt du es aus einem Terminal und er per Doppelklick ? Denn bei Doppelklick sollte bei der Art eigentlich immer die Shell-Konsole aufgehen.

Wenn nicht, könntest du mal die Parameter im Aufruf posten?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

@Xynon1
Aha, darin lag der Unterschied! Er hat das Script (grafische PyQt4-Anwendung) durch Doppelklicken gestartet, ich über die Konsole. Bei mir zeigt sich jetzt auch das Verhalten.
Wie sieht da die Lösung aus? -Ein Batch-Script schreiben und darin Python aufrufen?
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Hehe, darüber hatte ich beim schreiben auch schon nachgedacht, nur fällt mir dazu nichts ein. Theoretisch sollte das in einem Batchscript durch den Befehl "start /B" unterbunden werden, das die Konsole geöffnet bleibt.

Ich versteh aber auch nicht wieso man das Kopieren nicht direkt mit Python gehen sollte. Das wäre wesentlich sauberer.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Die Konsole bleibt zum Glück nicht geöffnet, sondern schließt sich nach dem Prozess-Ende. Bei kurzen Prozessen sieht man quasi nur ein schwarzes Fenster aufblinken.
Start /B kannte ich noch garnicht
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Mit xcopy wirst du warscheinlich auch nichts besseres hinbekommen, denn das ist auch nur eine Win32-Konsolen Programm. AFAIK konnte man die Konsole nur mit der Windows-API aus "user32.dll" mit der Funktion "ShowWindow" ausblenden oder musste eine FreeConsole nutzen. Beides ist aber bei xcopy nicht der Fall und da xcopy schon ein Kompilat ist, wirst du das auch nicht ändern können. Somit wird diese immer "aufpoppen", eventuell kannst du noch /MIN an start ranhängen, dann wird sie minimiert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Ok, ich rufe mit dem Programm aber auch einen proprietären Compiler, ein Komprimierungstool für Images und einen EEPROM-Flasher auf. Also bringt es nicht viel wenn ich xcopy in native Python-Code nachprogrammiere und die anderen Tools nicht.
Wenn ich das Programm aus einem Batch-Script heraus aufrufe funktioniert es soweit super. Es öffnet sich nur ein einziges Konsolenfenster. Damit kann ich erstmal Leben.
Werde mir die Subprocess-Klasse aber nochmal genau anschauen...
BlackJack

@twessels: Grundsätzlich ist das Konsolenfenster eine Entscheidung von Windows wenn es ein Programm startet. Es wird zwischen Konsolen-Programmen und Windows-Programmen unterschieden. Diese Information holt sich Windows aus der jeweiligen `*.exe`. Irgendwie kann man mit dem `creationflags`-Argument aber wohl unter Windows auch bei Konsolen-Programmen verhindern dass da ein Konsolenfenster erstellt wird. Damit wird der Code an der Stelle dann plattformabhängig.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@BlackJack
Hatte ich oben schon zwei Methoden genannt wie man das in Windows machen könnte. Theoretisch könnte man auch einen Dienst statt einen Konsolen-Programm schreiben. Aber für die Methoden bräuchte man immer den Sourcecode.
Irgendwo gab es auch noch ein Zusatztool namens HideConsole, oder so ähnlich, welches von außen die Konsole verbirgt.

Edit: http://beta.unclassified.de/projekte/hideconsole/
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
snafu
User
Beiträge: 6833
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Der Quelltext besteht aus wenigen Zeilen. Das dürfte also auch mittels ``ctypes`` umsetzbar sein.
Gremlin
User
Beiträge: 166
Registriert: Freitag 28. Mai 2010, 23:49

BlackJack hat geschrieben:Irgendwie kann man mit dem `creationflags`-Argument aber wohl unter Windows auch bei Konsolen-Programmen verhindern dass da ein Konsolenfenster erstellt wird.
Ich bin mal (wieder) so frei:

Code: Alles auswählen

p = Popen(cmd, bufsize=1, cwd=exec_dir, stderr=subprocess.STDOUT, stdout=PIPE, creationflags=0x08000000)
BlackJack hat geschrieben:Damit wird der Code an der Stelle dann plattformabhängig.
Das ist er doch sowieso schon? (xcopy)
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Hallo, so funktioniert es. Ganz ohne Batch-Script.
Man beachte

Code: Alles auswählen

import subprocess
import _subprocess

Code: Alles auswählen

	def runProcess(self, cmd, name):
		try: 
			exec_dir = os.getcwd()
			if verboseFlg:
				if gui == True:
					# self.printer("opening process %s" % " ".join(cmd), self.tabNum, myout['std'])

					# do not show window
					info = subprocess.STARTUPINFO()
					info.dwFlags = _subprocess.STARTF_USESHOWWINDOW
					info.wShowWindow = _subprocess.SW_HIDE
					
					# open process and redirect stderr to stdout and stdout to pipe
					p = Popen(cmd, bufsize=1, cwd=exec_dir, stderr=subprocess.STDOUT, stdout=PIPE, startupinfo=info)
					# self.printer("process opened", self.tabNum, myout['std'])
					
					#reading from pipe
					with p.stdout as f:
						# self.printer("reading to buffer", self.tabNum, myout['info'])
						read_data = f.read() # read() blocks until buffer is full or subprocess returns
						self.printer(read_data, self.tabNum, myout['ext'])
					f.closed
					# self.printer("process closed", self.tabNum, myout['std'])
					
				else:
					subprocess.check_call(cmd, bufsize=1, cwd=exec_dir)
			else:
				fnull = open(os.devnull, "w")
				subprocess.check_call(cmd, bufsize=1, cwd=exec_dir, stderr=fnull, stdout=fnull)
				fnull.close()
		except subprocess.CalledProcessError,e:
			self.printer("%s failed" % name, self.tabNum, myout['err'])
		else:
			# self.printer("%s finished" % name, self.tabNum, myout['std'])
			pass
		
meine xcopy Funktion ist übrigens wohl plattformunabhängig:

Code: Alles auswählen

	def xcopy_(self, src, dst, recursive=True):
		if os.name == 'nt':
			# Y=Unterdrückung Bestätigungsaufforderung, E=Rekursiv, I=Annahme, dass Ziel ein Verzeichnis ist, C=Continue bei Fehler
			cmd = ['xcopy', '/Y', '/E', '/C', src, dst] if recursive==True else ['xcopy', '/Y', src, dst]
			self.printer(" ".join(cmd), self.tabNum, myout['std'])
			self.runProcess(['cmd.exe', '/C', 'echo d', '|'] + cmd, " ".join(cmd))
		elif os.name == 'posix':
			cmd = ['cp', '-R', src, dst] if recursive==True else ['cp', src, dst]
			self.runProcess(['cmd.exe', '/C', 'echo d', '|'] + cmd, " ".join(cmd))
		else:
			try:
				self.printer("copytree %s %s" % (src, dst), self.tabNum, myout['std'])
				shutil.copytree(src, dst, ignore='.svn') if recursive==True else shutil.copy2(src, dst)
			except (IOError, OSError), why:
				print str(why)
		
BlackJack

@twessels: Hm, bei Python 2.6, 2.7, und 3.1 bekomme ich ``ImportError: No module named _subprocess``. :?:
Benutzeravatar
snafu
User
Beiträge: 6833
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Zudem gibt es (getestet in 2.6) auch kein Attribut namens ``STARTUPINFO``.

EDIT: Der betreffende Code bestand mal, wurde dann aber rausgenommen. Und ``STARTUPINFO`` besteht nur unter Windows, ist aber (wie im Link erwähnt) nicht dokumentiert, sodass sich auch nicht drauf verlassen werden sollte.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

twessels hat geschrieben:

Code: Alles auswählen

        elif os.name == 'posix':
            cmd = ['cp', '-R', src, dst] if recursive==True else ['cp', src, dst]
            self.runProcess(['cmd.exe', '/C', 'echo d', '|'] + cmd, " ".join(cmd))
Sag mal wie wird cmd.exe bei dir unter unixoiden Systemen ausgeführt ?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Ich hab
Python 2.7 am Laufen.

Hier hab ich das Snippet her:
http://stackoverflow.com/questions/4703 ... showwindow

Code: Alles auswählen

import subprocess	# to execute external programs
print(subprocess.__file__)
import _subprocess
Wenn ich mit

Code: Alles auswählen

print(_subprocess.__file__)
versuche den Pfad zu erhalten, krieg ich allerdings einen Fehler.
Ich glaube durch das '_' wird Python darüber informiert, dass er eine alte Version der Lib benutzen soll
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Xynon1 hat geschrieben: Sag mal wie wird cmd.exe bei dir unter unixoiden Systemen ausgeführt ?
:P, copy&paste fehler. Teste das Tool nicht sehr häufig unter Linux
Antworten