您遇到的問題是 '生', '熟' 和 '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