且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么不Python的表现时,标准输出和标准输入重定向预期?

更新时间:2023-11-18 09:36:22

这是不是一个错误,这是一个特点。 : - )

Python的设置和放大器;用法,第1.1.1节接口选项(强调):


  

该间preTER界面类似于UNIX的外壳,但提供调用的一些额外的方法:


  
  

在标准输入名为连接到一个tty设备,它提示输入命令并执行他们直到EOF(结束文件中的一个字符,可以产生与UNIX按Ctrl-D或按Ctrl-Z,Enter键在Windows上)被读取。


  
  

当一个文件名参数名为或以文件作为标准输入,它读取并从该文件执行脚本。


块引用>

一个管既不是一个文件也不是tty设备,但它看起来像一个文件尽可能的C标准库(以及Python)的关注。因此第二行为踢和Python试图读取到文件的末尾。因为我们从来没有收我们的末端治理,这永远不会发生。

这行为不是在我看来,(或至少不能在Windows)特别懂事,如果你想,你可以提交一个bug。我猜想,这样的建议将被拒绝,因为任何变化将打破向后兼容性,但我可能是错的。

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

 蟒蛇-i

这使得Python的进入互动模式,尽管标准输入不是终端

Unfortunately,没有已知的方法,使看起来像在Windows终端的管。

I try to redirect in windows the cmd.exe stdout&stdin (with CreateProcess()). It works fine as long as I run simple commands or open GUI apps, but if I try running a software like python, it does not give me it's output anymore (nor getting the input through stdin).

Code example:

#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");
}

It's not a bug, it's a feature. :-)

From Python Setup & Usage, section 1.1.1, Interface options (emphasis added):

The interpreter interface resembles that of the UNIX shell, but provides some additional methods of invocation:

When called with standard input connected to a tty device, it prompts for commands and executes them until an EOF (an end-of-file character, you can produce that with Ctrl-D on UNIX or Ctrl-Z, Enter on Windows) is read.

When called with a file name argument or with a file as standard input, it reads and executes a script from that file.

A pipe is neither a file nor a tty device, but it looks like a file as far as the C standard library (and hence Python) is concerned. So the second behaviour kicks in, and Python attempts to read to the end of file. Since we never close our end of the pipe, that never happens.

This behaviour isn't particularly sensible in my opinion (or at least not in Windows) and you could file a bug if you wanted. I would guess that such a proposal would be rejected, since any change would break backwards compatibility, but I could be wrong.

You can work around the problem by providing the -i option on the command line:

python -i

That makes Python enter interactive mode, despite the fact that stdin isn't a terminal.

Unfortunately, there is no known way to make a pipe that looks like a terminal on Windows.