任务分解
ANSI
简易进度条
总结
参考

如何实现一个命令行的进度条

August 08, 2020

很多CLI工具为了提高DX,在做耗时长的工作时,都会在命令行显示一个进度条。web端的进度条写多了,命令行的进度条还没写过,所以这里造个简易轮子,了解下原理。

任务分解

分解下任务,要实现一个进度条,要做到以下工作

  1. 传入一个进度数值X,绘制100%的进度容器和X%的进度条部分部分 这个实现简单,只需要 X% 部分和(100-X)%部分的字符不同即可。
  2. 每次进度变化,清除当前已绘制部分,绘制更新后的进度内容 在浏览器端实现这点很容易,清除绘制部分都由渲染进程处理,在命令行终端可以用 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 forecolor = [];
    const backcolor = [];
    
    for (let i = 30; i <= 37; i++) {
    forecolor.push(i, i + 60);
    backcolor.push(i + 10, i + 70);
    }
    
    for (let f of forecolor) {
    let str = '';
    for (let b of backcolor) {
      str += `\x1b[${f};${b}m A `;
    }
    str += `\x1b[2k`;
    console.log(str);
    }

其它具体的转义码参考 维基百科,现在画笔画板都有了,图怎么画就看画家的手了。

简易进度条

有了以上的前置知识,写了简单的进度条就简单了

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也可以命令行内写画骚操作。

github地址

参考

ANSI 转义序列


feiker 少年起而行之