Linux深入探索01-stty與鍵盤訊號

—– 最近更新【2021-12-20】—–

一、簡介

最初的 Unix 設定假定人們使用終端連接主機電腦。30多年過去後,情況依然如此,即便是在自己的PC機上運行Unix。多年以來,終端發展為許多不同的類型,並且提供了許多不同類型的鍵盤,但是Unix一直能夠很好地使用它們。這是因為Unix使用了一個鍵盤映射系統,該系統非常靈活,可以用於任何類型的鍵盤。

所謂的鍵盤映射系統也就是使用一組標準的鍵盤訊號。儘管這些訊號是標準的,但是發送這些訊號所需按下的鍵卻可以根據需要修改,而GNU所提供的stty(set tty)則是可以對這些按鍵進行修改的工具。

通俗一點來說,鍵盤映射就是當你按下某個或者某些按鍵的時候,就會給你的系統發送設定的訊號。比如在Unix中,字元映射到 intr(interrupt,中斷) 訊號上。這也就是說,當按下時,它的效果就是發送 intr(終止程式) 訊號。

本節要介紹的stty命令就是可以用來查看或者修改當前的鍵盤映射。

註:
<Ctrl-C>表示按住鍵盤的Ctrl鍵並按下C字母鍵。當然,還有一些其它的表示方法,如:^C 或者 Ctrl-C 等。

二、stty語法

stty – change and print terminal line settings(stty命令用於顯示和修改終端行設置)

Usage: stty [-F DEVICE | --file=DEVICE] [SETTING]...
  or:  stty [-F DEVICE | --file=DEVICE] [-a|--all]
  or:  stty [-F DEVICE | --file=DEVICE] [-g|--save]

更詳細的用法可以使用 man stty 或者 stty --help 查看。

三、常見的鍵映射

如下所列出的鍵映射都是最常見的鍵映射,但是它們不是固定的。

訊號 作用
erase / / ^H 刪除鍵入的最後一個字元
werase ^W 刪除鍵入的最後一個單詞
kill ^X / ^U 刪除整行
intr ^C 停止正在運行的程式
quit ^\ 停止程式並保存core文件
stop ^S 暫停螢幕顯示
start ^Q 重新啟動螢幕顯示
eof ^D 指示已經沒有數據(停止shell,即退出登錄)
susp ^Z 暫停一個程式(掛起)

註:
由於字面意思的理解,kill鍵盤訊號很容易被誤認為是停止程式,但它的作用只是刪除你剛鍵入的一行。為了停止程式的話,你需要使用的是intr訊號。

四、stty使用

1、查看鍵映射

使用stty -a查看系統的鍵盤映射情況

root@instance-2:~# stty -a
speed 38400 baud; rows 23; columns 110; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

註:
這個^?並不是一個真正的鍵組合。也就是你不能按住<Ctrl>鍵再按?(問號)鍵。^?表示「whichever key on your keyboard that sends the code that used to be called DEL(你的鍵盤上某個用來發送DEL程式碼的鍵)」。

需要時,這裡顯示的各種選擇都可以重新配置。每種終端選項都有自己的名字(如ixon),其中大多數要麼被設置要麼被清除。在stty中相應選項前冠以負號(-),該選項被清除(禁止);如果無負號,該選項被設置。 當希望修改各選擇的值時,應在stty命令中正確書寫相應選項。如:

$ stty -ixon    # 將流控制設置為OFF
$ stty ixon    # 則將其置為ON。在stty命令中可以同時設置多個選項: 
$ stty ixon 1200    # 該命令將終端設置為1200波特,並將流控制置為ON。

2、修改鍵映射

修改鍵映射,只需要使用命令stty,後面跟著要修改訊號的名稱,然後是新的鍵賦值即可。

例如,將kill訊號修改為^U的命令如下:

stty kill ^U

3、其它設置

1)回顯設置

stty -echo    #關閉回顯。比如在腳本中用於輸入密碼時。
stty echo     #打開回顯。

2)列印當前終端的大小(行數和列數)

root@Chan:~# stty size
38 191

3)在命令行下禁止輸出小寫

stty olcuc     #開啟
stty -olcuc    #恢復

4)忽略回車符

stty igncr    #開啟
stty -igncr   #恢復

五、常見鍵盤映射問題

1、解決backspace鍵映射問題

1)在linux/unix平台上的命令行介面中:
當你輸錯了字元,要想刪除,然後習慣性的按下backspace鍵後,發現非但沒有刪除想要刪掉的字元,還多出了兩個字元^H

2)問題原因:
在你的電腦上鍵等同於^H,但是在遠程主機上^H鍵沒有被映射到erase訊號上(^?映射到erase上了)。

3)解決方法:
方法一:
修改連接遠程主機的程式的配置(如你使用的ssh客戶端程式)。大多數通訊程式允許控制鍵發送^H還是發送^?
方法二:
這可以通過使用stty命令修改tty終端的設置來實現backspace刪除功能。

stty erase ^H

如果你希望下次登錄時還是使用這個設置,這時你需要將這條設置命令放置到你的初始化文件中(一般是你的.profile文件)。

2、封閉 eof

大部分shell是用^D來映射 eof訊號,但有些時候你只是不小心按了<Ctrl-C>,然後就給你註銷登錄了。
想要避免這種情況發生,可以設置讓shell封閉eof訊號。
在Bash shell中,可以設置環境變數$IGNOREEOF,方法如下:

linux1@noseeu:~$ export IGNOREEOF=5
linux1@noseeu:~$ echo $IGNOREEOF
5
linux1@noseeu:~$ Use "logout" to leave the shell.
linux1@noseeu:~$ Use "logout" to leave the shell.
linux1@noseeu:~$ Use "logout" to leave the shell.
linux1@noseeu:~$ Use "logout" to leave the shell.
linux1@noseeu:~$ Use "logout" to leave the shell.
linux1@noseeu:~$ logout

連接斷開

此時,你只有連續按5次<Ctrl-C>才會註銷你的登錄。

六、參考:

書箱:《Unix & Linux 大學教程》第七章 (美)Harley Hahn 著 張傑良 譯
GNU手冊:man stty
中文手冊://linux.51yip.com/search/stty
英文資料:The TTY demystified(解密TTY)
SegmentFault: Linux TTY/PTS概述