2012-09-01 35 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已經重定向的文件描述符。