2016-06-03 26 views
0

auf Python 3.5.1, ich habe folgendes:Python Standard IO Subprocess

output = subprocess.check_output(cmd).decode(encoding="UTF-8") 

Dies ruft die ordnungsgemäß Befehl aufgerufen cmd. C++ 14-Code in cmd wie folgt aussieht:

HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 
assert(handle!=INVALID_HANDLE_VALUE); //Always passes 
assert(handle!=nullptr);    //Always passes 

CONSOLE_SCREEN_BUFFER_INFO csbi; 
BOOL result = GetConsoleScreenBufferInfo(handle,&csbi); 
assert(result!=0); //Always fails. `GetLastError()` returns 6 (invalid handle) 

den oben Python-Code Ausführen das subprocess verursacht cmd bei der angegebenen Linie zum Scheitern verurteilt. Gemäß den Python-Dokumenten sollte in diesem Fall das stdout/stderr vom übergeordneten Prozess (d. H. Dem Python-Interpreter) geerbt werden. Also sollte es nicht. In der Tat funktioniert das obige für z.B. printf Ed-Ausgabe.

ausdrücklich auch umleiten Der Versuch schlägt fehl:

#Traceback (most recent call last): 
# File "C:\dev\Python35\lib\subprocess.py", line 914, in __init__ 
# errread, errwrite) = self._get_handles(stdin, stdout, stderr) 
# File "C:\dev\Python35\lib\subprocess.py", line 1145, in _get_handles 
# c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) 
#io.UnsupportedOperation: fileno 
p = subprocess.Popen(cmd.split(" "),stdout=sys.stdout,stderr=sys.stderr) 

#Using `subprocess.PIPE` instead fails in the same way as the `subprocess.check_output(...)` 
#example originally given above. 

Was falsch los ist? Wie repariere ich es?

+1

'check_output' setzt' stdout = PIPE'. Sie können dieses Handle nicht mit Konsolenfunktionen wie 'GetConsoleScreenBufferInfo' und' WriteConsole' verwenden. 'printf' funktioniert, weil es' WriteFile' aufruft, das Bytes in jede Art von Datei-Handle schreibt. – eryksun

+1

Ist 'sys.stdout' ein Dateiobjekt in einer IDE? In diesem Fall handelt es sich nicht um eine Betriebssystemdatei mit einem Handle, die in den Standardhandles des untergeordneten Prozesses vererbt werden kann. Wenn Ihr C++ - Code darauf zurückgreift, C-Standard-I/O zu verwenden (vorzugsweise unbuffered), wenn es sich bei stdout nicht um eine Konsole handelt, kann Ihr Python-Code einen Thread verwenden, um aus der Pipe 'p.stdout' zu lesen. 'check_output' und' Popen.communicate' machen das für dich, aber du brauchst vielleicht etwas interaktiveres. – eryksun

+2

@HarryJohnston, wir wissen, dass 'sys.stdout' nicht mit einer Windows-Datei (Konsole, Pipe, Festplatte) verbunden ist, weil es kein' fileno() 'hat. Ich denke, imallett möchte, dass die Standardausgabe des Child-Prozesses in Pythons 'sys.stdout' auftaucht, unabhängig davon, was' sys.stdout' ist (zB 'sys.stdout' könnte ein Proxy-Objekt sein, das mit dem interaktiven Fenster einer IDE kommuniziert ein Rohr oder eine Steckdose). In diesem Fall kann ein Thread "p.stdout.read (1)" oder "p.stdout.readline()" durchlaufen und in "sys.stdout" schreiben. – eryksun

Antwort

2

Eine Pipe ist keine Konsole. check_output() verwendet intern stdout=PIPE. Die Konsolenausgabe wird nicht umgeleitet (erstellt von WriteConsoleW()).

Der erste Fehler (ungültige Handle) schlägt vor, dass die Standardausgabe nicht das Konsolengerät ist.

Es sei denn, es ist ein gewünschtes Verhalten (to print outside of the standard output); Verwenden Sie WriteFile() wenn stdout is not a console device.

Der zweite Fehler (io.UnsupportedOperation: fileno) legt nahe, dass sys.stdout keine richtige Datei ist und daher können Sie es nicht als stdout Parameter auf einen Teilprozess übergeben (Sie können redirect subprocess' stdout using stdout=PIPE and print the output using print() or sys.stdout.write() method directly).

+0

Nach ein bisschen Lesen außerhalb dieser Antwort denke ich, was ich wirklich wollte, war für 'cmd', die vom Python-Interpreter geöffnete Konsole zu verwenden. Da 'cmd' ein Unterprozess ist, bin ich mir nicht sicher, ob der Wunsch sinnvoll ist. Beim Aufruf von' cmd' scheint 'cmd' jedoch sein eigenes Konsolenfenster zu öffnen (ein neues wird angezeigt, wenn es ausgeführt wird). Kannst du bitte stattdessen erklären, warum 'cmd' dieses Fenster nicht erkennt und darauf schreibt, wenn es zum Beispiel keine Umleitung im Python-Aufruf gibt? – imallett

+0

@imallett: "Wie eine C++ - Anwendung die Konsole verwenden kann, die von ihrem übergeordneten Python-Skript (über Subprozess) geöffnet wird" klingt wie eine gute Frage, aber es wäre das dritte Problem (versuchen Sie, Ihre Fragen auf ein einzelnes Problem pro Frage zu beschränken). Hast du das Offensichtliche versucht? (stdout nicht umleiten, einfach den 'stdout' Parameter nicht übergeben, z. B. 'subprocess.check_call (cmd)' - der Subprozess sollte in diesem Fall auf die Konsole drucken). Es scheint auch, dass Ihr Code davon ausgeht, dass das stdout die Konsole ist (ich habe es anfangs verpasst - ich habe die Antwort entsprechend aktualisiert). – jfs

+0

Ich wollte nicht fragen, wie ich die Konsole der Eltern benutzen könnte, denn das wäre in der Tat eine separate Frage. Ich meinte, ich wusste nicht, wie das, was ich getan habe, fehlgeschlagen ist. Der Versuch, das vorgeschlagene 'subprocess.check_call (cmd)' zu verwenden, funktioniert (die Assertionen werden übergeben und die Ausgabe wird an die Konsole ausgegeben). Wenn es umgeleitet wird, stürzt es ab. Ich glaube, ich verstehe: Das Handle wird aus dem Stdout-Handle generiert. Wenn es umgeleitet wird, ist das eine Pipe, keine Datei, die in ein Terminal geleitet wird. Das Terminal existiert also immer noch, aber da stdout nicht an es angehängt ist, wird durch das Erhalten des Handle stattdessen die Pipe zurückgegeben, so dass terminalische Dinge scheitern. Ja? – imallett