您遇到的问题是 '生', '熟' 和 'CBREAK' 模式之间的差异。这些模式是内核级终端驱动程序的模式,而不是您的应用程序代码模式或标准库或用户空间中的任何其他模式。
在cooked模式下,终端驱动程序本身具有内置的基本线路编辑功能。它可以处理退格,单词擦除(基本上可以立即退回整个单词)和类似的事情。没有像处理箭头键或历史或任何类似的东西复杂。很原始。在这种模式下,你的程序从不会看到终端上的任何内容,直到发送行尾(eol)字符,然后你的程序得到一整行,并且行结束被转换为Unix标准\n
,而不管终端实际上是。此外,作为其中的一部分,终端驱动程序会将键入的字符回显给终端,以便用户可以看到他们正在键入的内容。
在'cooked'模式下,内核级终端驱动程序也会进行一些输出转换。如果需要,其中一部分将\n
转换为\r\n
。终端驱动程序处理特殊字符,如Control-C(向控制进程组发送SIGINT(由CPython转换成KeyboardInterrupt异常))和Control-Z(发送一个SIGTSTP(如一个SIGSTOP,但可以被捕获)到控制进程组)。
在'cbreak'模式下,不再进行行编辑。终端驱动程序会立即向程序提供每个字符(或短字符序列,如箭头键的转义序列)。这些字符不会回显到屏幕,所以除非您的程序打印出来,否则用户将看不到它们。尽管终端驱动程序仍然处理特殊字符,如Control-C和Control-Z,但它不再处理线条编辑字符,如退格键或字擦除字符(通常为Control-W)。此外,某些输出处理仍然完成,所以驱动程序将\n
变成\r\n
。
在'原始'模式下,任何输入或输出都不进行处理。没有特殊的字符处理,没有回应,没有将\n
转换为\r\n
,没有处理Control-Z,没有任何处理。这取决于终端处于原始模式的程序来完成这一切。
现在,您正在设置sys.stdin
的属性,因此您可能认为这不应该影响sys.stdout
。但是,实际上,两个文件描述符都会导致终端驱动程序完全相同的“实例”。终端驱动程序的设置决定了发生的情况。因此,如果通过sys.stdin
,sys.stdout
甚至sys.stderr
更改这些设置,则所有更改相同的底层终端驱动程序实例并影响所有其他设备并不重要。
这当然不适用于在程序启动之前shell已经重定向的文件描述符。
到目前为止,这似乎是正确的;我的印象是,我不应该在Linux下手动插入'\ r'。谢谢 –
@halex你能否解释为什么在原始模式下需要这样做,但在正常打印时不需要?谢谢。 – Stefan