2012-09-01 34 views
4

我需要在Python中将标准输入切换到非缓冲模式,以便我可以读取单个字符。我设法让它工作,但是现在标准输出被破坏了:不管怎么样,在换行符之后,一些空格字符发出,第一行为零,第二行是3,第三行是6,等等。 :Python在原始模式标准输入打印添加空格

ASD 
    ASD 
     ASD 

操作系统是Ubuntu Linux 12.04,64位版本,Python版本是3.2.3。

我该如何摆脱这种行为?

下面是我使用的代码:

import sys 
import tty 
import termios 

fd = sys.stdin.fileno() 
old_settings = termios.tcgetattr(fd) 
tty.setraw(sys.stdin) 

for i in range(0, 10): 
    print("ASD") 

termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) 

回答

4

看起来你只是做了一个换行符,但没有回车。更改您的打印到

print("ASD", end="\r\n") 
+0

到目前为止,这似乎是正确的;我的印象是,我不应该在Linux下手动插入'\ r'。谢谢 –

+0

@halex你能否解释为什么在原始模式下需要这样做,但在正常打印时不需要?谢谢。 – Stefan

5

谷歌带我到这里时,当我正在寻找这个问题的答案。没有回车的halex所分享的线索帮助我寻找真相。我发现我的回答对克里斯的Wiki,一个帖子:https://utcc.utoronto.ca/~cks/space/blog/unix/CBreakAndRaw导致我读tty.py这里来源:https://hg.python.org/cpython/file/618ea5612e83/Lib/tty.py 这给我带来了这样的结论:如果我们的目标是读单个字符,而不是:

tty.setraw() 

用途:

tty.setcbreak() 
3

您遇到的问题是 '生', '熟' 和 '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已经重定向的文件描述符。