如何实现一个命令行的进度条
很多CLI工具为了提高DX,在做耗时长的工作时,都会在命令行显示一个进度条。web端的进度条写多了,命令行的进度条还没写过,所以这里造个简易轮子,了解下原理。
任务分解
分解下任务,要实现一个进度条,要做到以下工作
- 传入一个进度数值X,绘制100%的进度容器和X%的进度条部分部分
这个实现简单,只需要 X% 部分和(100-X)%部分的字符不同即可。
- 每次进度变化,清除当前已绘制部分,绘制更新后的进度内容
在浏览器端实现这点很容易,清除绘制部分都由渲染进程处理,在命令行终端可以用 ANSI 转义序列控制字符绘制,具体可以参考 维基百科
简单来说,ANSI 就是控制终端输出的色彩、样式、光标位置以及控制终端行为的特殊字节. 一个ANSI转义字符通常以 \x1b[
开头,\x1b[
也叫做 CSI (Control Sequence Introducer), CSI
后面跟不同的编码可以表示不同的字符格式。
ANSI
For Many Examples,
-
显示红字
echo '\x1b[31;m hello world!'
-
光标移动,清除整行
echo "hello world \x1b[2K"
-
来一手五彩斑斓的A

其它具体的转义码参考 维基百科,现在画笔画板都有了,图怎么画就看画家的手了。
简易进度条
有了以上的前置知识,写了简单的进度条就简单了
const prefix = '['; const postfix = ']'; const MAX_CHARS = 40; function render(precent: number) { const arrowNumber = ~~(MAX_CHARS * precent); const bar = '>'.repeat(arrowNumber) + ' '.repeat(MAX_CHARS - arrowNumber); const curProcessbar = `\x1b[1A\x1b[2K${prefix}${bar}${postfix} ${Math.floor( precent * 100 )}%`; console.log(curProcessbar); } let cur = 0; const timer = setInterval(() => { if (cur >= 100) { clearInterval(timer); return; } cur++; render(cur / 100); }, 16);
给你点 color 看看
const MAX_CHARS = 40; function render(precent: number) { const arrowNumber = ~~(MAX_CHARS * precent); const bar = '\x1b[31m' + '▓'.repeat(arrowNumber) + '\x1b[34m' + '░'.repeat(MAX_CHARS - arrowNumber); const curProcessbar = `\x1b[1A\x1b[2K${bar} ${Math.floor(precent * 100)}%`; console.log(curProcessbar); } let cur = 0; const timer = setInterval(() => { if (cur >= 100) { clearInterval(timer); return; } cur++; render(cur / 100); }, 16);
总结
ANSI转义序列(ANSI escape sequences)是一种带内信号的转义序列标准,用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列,大部分以ESC转义字符和”[“字符开始,终端会把这些字节序列解释为相应的指令,而不是普通的字符编码。
命令行也是终端一种,对用户可视的都是前端范畴,学会了ANSI也可以命令行内写画骚操作。