終端上退格鍵的行為
這是關於退格 (
\b
) 字元的行為。我有以下 C 程序:int main() { printf("Hello\b\b"); sleep(5); printf("h\n"); return 0; }
我的終端上的輸出是
Helho
隨著游標前進到下一行的第一個位置。
首先,整個內容僅在 5 秒睡眠後列印,因此我推斷從核心到終端的輸出是行緩衝的。所以現在,我的問題是:
- 由於
\b\b
回到兩個空格,到 (second) 的位置l
,然後類似於如何l
替換為h
,o
應該已替換為\n
。為什麼不是?- 如果我刪除 line
printf("h\n");
,它會列印Hello
並返回兩個字元,而不刪除。我從其他答案中得到的這是因為非破壞性退格。為什麼輸入和輸出的這種行為不同?也就是說,如果我在終端中輸入一些東西(即使是同一個程序)並按 Backspace,它會刪除最後一個字元,但不會刪除輸出。為什麼?如果有幫助,我正在使用 bash 的 xterm 終端上的 Ubuntu 系統上。
首先,整個內容僅在 5 秒睡眠後列印,因此我推斷從核心到終端的輸出是行緩衝的。
不,從您的程序到核心的輸出是行緩衝的。
stdio
這是whenstdout
是終端的預設行為。添加呼叫setbuf(stdout, NULL)
以關閉stdout
. 見setbuf(3)
。
- 由於
\b\b
回到兩個空格,到l
then 的位置類似於如何l
被替換h
,o
應該已經被替換\n
。為什麼不是?因為換行符只是移動游標(並滾動螢幕),所以它不會作為一個可見的字元列印出來,它會在終端上佔據一個字形的位置。如果我們假設它會取代字形,它會是什麼樣子?
- 如果我在同一個程序中輸入一些內容,然後按 Backspace,它會刪除最後一個字元,但不會刪除輸出。為什麼?
好吧,當您鍵入時會發生什麼取決於終端處於什麼模式。粗略地說,它可以處於通常的“熟”模式,終端本身提供基本的行編輯(處理退格);或者在“原始”模式下,所有按鍵都轉到應用程序,由應用程序決定如何處理它們,以及輸出什麼作為響應。熟模式通常伴隨著“本地回顯”,終端(使用者本地)在輸入字元時列印出字元。在原始模式下,應用程序通常負責回顯鍵入的字元,以完全控制可見的內容。
有關終端模式的討論,請參見例如這個問題: “原始”和“熟”設備驅動程序之間有什麼區別?
如果您執行 eg
cat
,終端將處於熟模式(預設)並處理行編輯。例如,點擊x``Backspace``Ctrl-D
將導致cat
僅讀取空輸入,表示輸入結束。您可以使用strace
. 但是,如果您改為執行互動式 Bash shell,它將自行處理退格,並輸出它認為適合執行使用者期望的操作,即擦除一個字元。
strace -etrace=read,write -obash.trace bash
這是輸入上述序列後的部分輸出x``Backspace``Ctrl-D
:read(0, "x", 1) = 1 write(2, "x", 1) = 1 read(0, "\177", 1) = 1 write(2, "\10\33[K", 4) = 4 read(0, "\4", 1) = 1
首先, Bash
read
s 和write
sx
,將其輸出到終端。然後讀取退格符(八進制的字元程式碼 0177 或十進制的 127),並輸出退格符(八進制 010,十進制 8 ())將游標向後移動並*輸出清除行尾的控制序列,*<ESC>*[K
. 最後一個\4
是Ctrl-D
,Bash 使用它來退出程序。(* 在輸入中,
Ctrl-H
將具有十進製字元程式碼 8。退格與此處相同或 127,再次取決於終端的設置方式。)相比之下,相同的實驗
cat
只顯示了一次讀取零字節,即“文件結尾”條件。文件結束可能意味著連接的管道或套接字被關閉,文件的實際結束,或者Ctrl-D
在熟模式下從終端接收:read(0, "", 131072) = 0
特別是,
cat
看不到x
,也看不到退格,也看不到Ctrl-D
: 它們由終端處理。這可能是核心中的虛擬終端驅動程序;通過串列連接等的實際物理終端;或者像 xterm 這樣的終端仿真器,可以在同一台機器上執行,也可以在 SSH 連接的遠端端執行。這對使用者空間軟體無關緊要。