Nodejs 与 终端

最近需要使用Nodejs在终端中做一些显示内容方面的工作,这方面以前很少接触,查阅了相关资料,反而对与终端这种神奇的东西了解更多,这里做一个备忘。如果有人也涉及到这方面的内容,也有所查阅。

目前我们所能够在操作系统中看到的,都称之为“终端模拟器”,如下图:

这是Mac OS X系统中自带的终端模拟器,Linux中亦然。通常情况下,我们在使用nodejs显示终端内容时无非使用 console.log("string") 这样的语句在终端中打印一些内容。而Linux中,经常会看到如进度条等样式的内容,npm的install命令也是如此。那么这些进度条等样式是如何在终端中出现的呢。

答案就在于一组叫做“终端控制符”的命令符号。

究其“终端控制符”的出现是因为早期计算机设备用户都会通过网络访问一台公用主机,而用户手中只有一台“显示器”和输入设备(早期的键盘)。但不同的“显示器”与键盘硬件上互不兼容。这就导致显示的内容可能会不一致。最起码是样式上不一致。此时就会导致非常多的问题,所以当时出现了“终端控制符”这种协议。事实上协议非常多,但是后来用的最多的是vt100

再后来,操作系统中对终端进行模拟,这就是我们现在所说的模拟终端。模拟终端中依然支持这些“终端控制符”,我们常用的 clear 清屏命令,事实上就是被转换为一组内容为 \33[2J 的控制符。与此同时更多的控制符可以执行颜色设置,简单绘图等多种命令。

在Nodejs中,如果你想实现清屏的效果,只需要执行如下代码即可:

console.log("\33[2J");

为了方便你查看效果,你可以再继续写一些代码,放置当前node进程被结束,如下面这样:

var process = require('process');

console.log("\33[2J");

process.stdin.on('readable', () => {
  var chunk = process.stdin.read();
  if (chunk !== null) {
    process.stdout.write(`data: ${chunk}`);
  }
});

process.stdin.on('end', () => {
  process.stdout.write('end');
});

这样运行后,你可以看到终端被“彻底”清屏了。

那么如何借助终端控制符制作一个类似于进度条的东西呢?可以借助 \33[K 控制符,它可以清楚当前光标所在的一行的内容。我们借助Nodejs的定时器,反复刷新界面即可实现一个进度条功能。下面是详细代码,非常简单。

var process = require('process');
var tty = require('tty');

var ws = new tty.WriteStream();
var width = ws.columns;

var head = "|";
var foot = "%";
var progress = "";
var num = 0;

function update()
{
	foot = num + "%";
	var len = width - head.length - foot.length - 1;
	var p = Math.ceil( num / 100 * len );
	progress = "";
	for(var i=0; i<len; i++)
	{
		if( i<=p )
		{
			progress += "=";
		}
		else
		{
			progress += " ";
		}
	}
	process.stdout.write(head+progress+foot+"\33[K\r");
	num+=5;
	if( num>100 )
	{
		process.stdout.write("\33[K\r");
		process.exit(0);
	}
}

setInterval(update,500);

运行效果

在Linux中,查阅终端控制符可以使用 man console_codes