A闪的 BLOG 技术与人文
最近需要使用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
。