当stdout和stdin被redirect时,为什么Python没有像预期的那样工作?

我尝试在Windowsredirectcmd.exe标准输出和标准input(使用CreateProcess())。 只要我运行简单的命令或打开GUI应用程序,它就可以正常工作,但是如果我尝试运行像python这样的软件,它不会再给我输出(也不会通过stdin得到input)。

代码示例:

#include <windows.h> #include <iostream> #include <string> #include <thread> using namespace std; HANDLE child_input_read; HANDLE child_input_write; HANDLE child_output_read; HANDLE child_output_write; void writeToPipe() { while (true) { DWORD bytes_written; string msg; getline(cin, msg); msg += '\n'; BOOL success = WriteFile(child_input_write, msg.c_str(), msg.size(), &bytes_written, NULL); if (!success) { break; } } } void readFromPipe() { while (true) { DWORD bytes_read; char buffer[512]; BOOL success = ReadFile(child_output_read, buffer, sizeof(buffer)-1, &bytes_read, NULL); buffer[bytes_read] = 0; if (!success) { break; } cout << buffer; } } void createCmdProcess() { PROCESS_INFORMATION process_info; STARTUPINFO startup_info; SECURITY_ATTRIBUTES security_attributes; // Set the security attributes for the pipe handles created security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); security_attributes.bInheritHandle = TRUE; security_attributes.lpSecurityDescriptor = NULL; CreatePipe(&child_output_read, &child_output_write, &security_attributes, 0); CreatePipe(&child_input_read, &child_input_write, &security_attributes, 0); // Create the child process ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); ZeroMemory(&startup_info, sizeof(STARTUPINFO)); startup_info.cb = sizeof(STARTUPINFO); startup_info.hStdInput = child_input_read; startup_info.hStdOutput = child_output_write; startup_info.hStdError = child_output_write; startup_info.dwFlags |= STARTF_USESTDHANDLES; CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info); } int main() { createCmdProcess(); thread t(writeToPipe); thread t2(readFromPipe); t.join(); t2.join(); system("pause"); } 

这不是一个错误,这是一个功能。 🙂

从Python的设置和用法,第1.1.1节,接口选项 (强调增加):

解释器接口类似于UNIX shell,但是提供了一些额外的调用方法:

连接到tty设备的标准输入被调用时,它会提示输入命令并执行它们直到EOF(文件结束符,可以在UNIX或Ctrl-Z上使用Ctrl-D,在Windows上输入)读。

当使用文件名参数或文件作为标准输入进行调用时,它将从该文件读取并执行脚本。

管道既不是文件,也不是tty设备,但是就C标准库(以及Python)而言,它看起来像是一个文件。 所以第二个行为踢了,Python试图读到文件的末尾。 由于我们从来没有关闭管道的末端,所以从未发生过。

这个行为在我看来(或者至少不是在Windows中)并不是特别明智的,如果你愿意,你可以提交一个bug。 我想这样的建议会被拒绝,因为任何改变都会打破向后兼容性,但我可能是错的。

您可以通过在命令行上提供-i选项来解决该问题:

 python -i 

这使得Python进入交互模式,尽管stdin不是终端。

不幸的是,没有已知的方法可以使Windows看上去像一个终端。