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

四月不見發表於2022-01-23

----- 最近更新【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
中文手冊:http://linux.51yip.com/search/stty
英文資料:The TTY demystified(解密TTY)
SegmentFault: Linux TTY/PTS概述

相關文章