2009-09-20

UNIX终端特殊输入字符

在用Linux时不止一次被各种控制字符困扰,今天决定清算一下,以下便是成果。

ASCII控制字符

ASCII控制字符(ASCII字符集中的0~37)一般显示为^X,其中X是相应控制字符代码值加64(8进制100)所构成的字符。比如BS(退格)显示为^H,因为BS + 64 = 8 + 64 = 72 = H。在终端里输入这些控制字符的方法是ctrl + X,这里的X不需要区分大小写。

这样就能解释为什么vim有时会显示诸如^M、^J这样的让人眼花的东西。先说一下文本文件的格式:MAC/UNIX/PC。MAC格式的文本文件用ASCII CR(回车,'\r')分隔行;UNIX格式用ASCII LF(换行,'\n');PC格式则用ASCII CR + LF("\r\n")。vim可以正确、利索地显示任一格式,不像Windows记事本那样不能对UNIX和MAC格式分行,但是如果文件中混合着这三种分隔符,vim似乎是以非常民主的方式(少数服从多数)选择其中一种作为行分隔符,落选的则显示为^X。比如,假如vim认为文件是MAC格式的,那么CR就是分隔符,LF则显示为^J;假如是UNIX格式,则CR被显示为^M。

UNIX终端特殊输入字符

有些ASCII控制字符在UNIX终端里是有特殊含义的,比如ASCII DC3(^S)表示STOP(从终端的观点看,STOP是一个字符的名称),意为停止输出,按下这个键后,无论再键入什么,终端也不会有任何回显,但实际上仍然是可以接受、执行命令行的,据说这项功能是为了在网络条件不好时减少掉线的情况。与之相对应的是ASCII DC1(^Q)表示START,意为恢复输出。所以,如果不小心按了ctrl + S,再按ctrl + Q就可以了。

然而我也碰过ctrl + Q死活不作为的情形,非常郁闷,不得不放弃那个会话,损失自是相当惨重。现在估计,那是因为终端的START字符被更改了,不再关联到^Q上。

是的,终端特殊字符到ASCII控制字符的映射几乎全部可以更改,除了CR(回车)和NL(换行)。《UNIX环境高级编程》表18-6是一个关于这些字符的详细清单。

^S <=> STOP 和 ^Q <=> START 只是典型情况,却非唯一。此外再比如^H <=> ERASE(删除字符),我曾经遇到过这种情况:进入sftp后,每次按BS键都蹦出来^H(也有时候是^?),急得一败涂地。

要更改终端特殊字符,在命令行中用stty命令可以很方便地做到,stty print or change terminal characteristics。针对刚才说的BS键回显成^H不起作用的情况,这样就可以了:

stty erase ^H

意思是,^H will erase the last character typed。

用stty -a可以print all current settings in human-readable form。

P.S. 并非只有ASCII控制字符才可以作为UNIX终端特殊字符,普通的可打印字符也可以,只不过这样做没有实际意义而已,如果执行stty erase b,那你每敲一个b就会吃掉上一个字符,自然也就没法上b这个字母上屏了。