CLIのプログレスバーを作ってみた
          はじめに
皆さん、こんにちは。株式会社BTMの風間と申します。
今回はCLIで動くプログレスバーを作成してみました。実際に作ったのはこちら。

コンソール(ターミナル)で、yum、apt、brewなどを利用したパッケージのインストールをされたことがある方は、こういった進行状況の表示をよく見ていると思います。
この進行状況の表示方法に以前から興味があったので、実際に作ってみて、使った方法をまとめてみました。
本記事で紹介する実装・実行は以下の環境にて行いました。
・Windows11
・WSL2(Ubuntu 22.04.3 LTS)
・Node.js 20.11.1
・Git Bash(推奨ウインドウサイズ Columns:80 x Rows:20)
実際のソース
// 実際の処理をsleepで代用
const sleep = async (ms) => new Promise(resolve => setTimeout(() => resolve(), ms));
// プログレスバーの処理
// 複数あるファイルの処理の進捗状況を表示する
const progressBar = async () => {
    const maxFileNum = 10; // 処理するファイルの最大数
    for (let i = 0; i <= maxFileNum; i++) {
        // 1行目に[処理済みのファイル数/全ファイル数]を表示する
        process.stdout.write(`[${i}/${maxFileNum}]\n`); 
        // 2行目に処理しているファイル名を表示する。今回は適当な名前を表示。
        process.stdout.write(`ファイル${i}\n`);
        // 3行目に処理しているファイルの進捗状況を表示する(ここでは処理開始前の状態)
        process.stdout.write('[--------------------]');
        // キャリッジリターンで3行目の先頭に戻り、処理の進行に合わせて#を表示する
        process.stdout.write('\r[');
        for (let j = 0; j < 20; j++) {
            process.stdout.write('#');
            await sleep(100); // 処理
        }
        // ファイルが残っている場合は行先頭に戻り、ANSIエスケープシーケンスを利用して2行上に移動する
        if (i !== maxFileNum) {
            process.stdout.write("\r\x1b[2A");
        }
    }
    process.stdout.write("\ncomplete\n");
};
progressBar();
実行方法
git bash上で、コマンド「node 上記ソースのファイル」を実行します。例)上記のソースが~/index.jsに保存してある場合、以下を実行
node ~/index.js
今回やったこと
その1 基本
プログレスバーはターミナルに文字出力で表現しています。1行目→2行目→3行目を表示し、再び1行目から繰り返します。3行目は全体長を先に表示し、処理に合わせて#で上書きします。文字位置制御には次の方法を使いました。
その2 行先頭から表示をやり直す(キャリッジリターン)
行先頭に戻す制御コード“\r”を利用します。
process.stdout.write("AAAAA"); // 画面上はAAAAA
process.stdout.write("\r");    // カーソルを先頭に移動
process.stdout.write("BB");    // 画面上はBBAAA
その3 3行書いたら1行目に戻る(ANSIエスケープシーケンス)
ANSIエスケープシーケンスでカーソル移動を行います。エスケープコード(0x1b)から始まります。
| 記法 | 内容 | 
|---|---|
| ESC[nA | カーソルを上にn移動 | 
| ESC[nB | カーソルを下にn移動 | 
| ESC[nC | カーソルを右にn移動 | 
| ESC[nD | カーソルを左にn移動 | 
process.stdout.write('AAAAA');   // AAAAA
process.stdout.write('\n');      // 改行
process.stdout.write('BBB');     // AAAAA↵BBB
process.stdout.write('\x1b[1A'); // 上に移動
process.stdout.write('CCCCC');   // AAACCCCC↵BBB
process.stdout.write('\x1b[1B'); // 下に移動
最後に
CLIで動くシンプルなプログレスバーを作ってみました。ANSIエスケープで文字色変更なども可能です。ぜひ試してみてください!
株式会社BTMではエンジニアの採用をしております。ご興味がある方はぜひコチラをご覧ください。
- 
              
SNS
 - 
              
投稿日
 - 
              
カテゴリー
Tech Blog