2014年3月29日星期六

详解并改进Linux终端的clear命令

clear做了啥?

clear做的工作很简单:把待输入的下一行移动到左上角。
所以你看,它根本没有真正对终端的内容进行清除,只不过是将其藏起来了。

如何实现clear

Linux的终端控制序列

Linux控制台实现了VT102和ECMA-48/ISO 6429/ANSI X3.64终端控制的子集,详见:console_codes - ubuntu man page
Linux使用ANSI escape code方式来描述其控制序列,详见:ANSI escape code - Wikipedia
简而言之,使用ESC符号开始的一串字符序列会被解析成控制序列,多数控制序列由CSI(control sequence introducer)开始,由ESC [来表示。

使用printf命令实现clear

printf支持终端控制序列,其中ESC可以用\e转义符表示。

console_codes - ubuntu man page中给出了一个表(节选):

Sequences Name Describe
ESC @ ICH Insert the indicated # of blank characters.
ESC A CUU Move cursor up the indicated # of rows.
ESC B CUD Move cursor down the indicated # of rows.
ESC C CUF Move cursor right the indicated # of columns.
ESC D CUB Move cursor left the indicated # of columns.
ESC E CNL Move cursor down the indicated # of rows, to column 1.
ESC F CPL Move cursor up the indicated # of rows, to column 1.
ESC G CHA Move cursor to indicated column in current row.
ESC H CUP Move cursor to the indicated row, column (origin at 1,1).
ESC J ED Erase display (default: from cursor to end of display).
ESC [ 1 J erase from start to cursor.
ESC [ 2 J erase whole display.

维基百科中ANSI escape code - Wikipedia中也说到:

CSI 2 J — This clears the screen and, on some devices, locates the cursor to the y,x position 1,1 (upper left corner).

CSI 2 JESC [ 2 J指令会在清除屏幕后将光标移动到第一行第一列(左上角)。
结合printf,得出以下命令:

printf "\e[2J"

不知道是不是Linux水土的问题,这个命令执行效果和描述不太一样,其实际效果是将当前行顶出屏幕外(负一行),并打印若干空白行(尼玛)。

为了修正这个问题,我们看到有个指令ESC H,描述如下:

Move cursor to the indicated row, column (origin at 1,1).

于是我们可以借助这个指令来完善我们的功能,修改如下:

printf "\e[H\e[2J"

这下终于完成我们坑爹clear命令。

难道就只是这样吗?

clear命令这么坑爹Linus Torvalds知道吗?
enter image description here

实现一个真正意义上的clear

console_codes - ubuntu man page中发现了另一个东西:

Sequences Name Describe
ESC c RIS Reset

重置你的终端来达到清除内容的效果。

printf "\ec"

真是一个简单又暴力的方法。
推荐写成shell脚本并移动到/usr/bin/目录下。


@LYC
转载请注明出处

0 评论:

发表评论