【发布时间】:2016-10-04 01:38:14
【问题描述】:
在 Python 3.5.1 上,我有以下内容:
output = subprocess.check_output(cmd).decode(encoding="UTF-8")
这会调用正确调用的命令cmd。 cmd 中的 C++14 代码如下所示:
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)
运行上述 Python 代码会导致子进程 cmd 在指定行失败。根据 Python 文档,在这种情况下,stdout/stderr 应该从父进程(即 Python 解释器)继承。所以,不应该。事实上,上面的工作很好,例如printfed 输出。
尝试显式重定向也会失败:
#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.
出了什么问题?我该如何解决?
【问题讨论】:
-
check_output设置stdout=PIPE。您不能将该句柄与GetConsoleScreenBufferInfo和WriteConsole等控制台函数一起使用。printf有效,因为它最终调用WriteFile,它将字节写入任何类型的文件句柄。 -
sys.stdout是 IDE 中的类文件对象吗?在这种情况下,它不是具有可以在子进程的标准句柄中继承的句柄的操作系统文件。如果您的 C++ 代码在 stdout 不是控制台时回退到使用 C 标准 I/O(最好是无缓冲行),那么您的 Python 代码可以使用线程从p.stdout管道中读取。check_output和Popen.communicate为您执行此操作,但您可能需要更具交互性的内容。 -
@HarryJohnston,我们知道
sys.stdout与Windows 文件(控制台、管道、磁盘)没有关联,因为它没有fileno()。我认为 imallett 希望子进程的标准输出显示在 Python 的sys.stdout上,无论sys.stdout是什么(例如,sys.stdout可能是使用管道或套接字与 IDE 的交互式窗口对话的代理对象)。在这种情况下,线程可以循环p.stdout.read(1)或p.stdout.readline()并写入sys.stdout。 -
@eryksun:没错。如果 OP 正在谈论我正在考虑的简单场景,那么对
.Popen的调用应该可以正常工作。至少,它对我有用。 :-)
标签: python c++ windows subprocess stdio