ブログ

Blog

CLIのプログレスバーを作ってみた

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
  • 投稿日
  • カテゴリー

    BTM Useful