やりたいこと
Windowsのbatファイルで進捗表示をしてみたいと思いました。
こんな感じの表示をしたいと思っています。
ざっくりいうと、
- 文字だけでプログレスバーっぽくする
- 改行せず、同じ行にとどまる。
がしたくて、同じ行にいかにしてとどまるかというサンプルとなります。
あくまでコンセプトを示しているだけで、そのままプログレスバーとして使えるわけではないかなと思っています。
コードのサンプル
実行するには下記をANSIエンコード、つまりShiftJISでbatファイルとして下記を保存してください。
@echo off
for /f %%a in ('"prompt $E& echo. |cmd /k"') do (set ESC=%%a)
echo 処理を実行しています。
echo __________ 0%% %ESC%[1A
timeout 1 >NUL
echo ++________ 20%% %ESC%[1A
timeout 1 >NUL
echo ++++______ 40%% %ESC%[1A
timeout 1 >NUL
echo ++++++____ 60%% %ESC%[1A
timeout 1 >NUL
echo ++++++++__ 80%% %ESC%[1A
timeout 1 >NUL
echo ++++++++++ 100%% %ESC%[1A
timeout 1 >NUL
echo %ESC%[1A%ESC%[1M処理が完了しました。%ESC%[1B%ESC%[1M%ESC%[1A
pause
説明
Windowsのコマンドプロンプトの VT100制御文字の機能を使っています。
詳細はMicrosoft社のコンソールの仮想ターミナルシーケンスのページ をご参照ください。
仮想ターミナルシーケンスの機能を使うとESC文字 (ASCIIコード 0x1Bの制御文字)から始まる文字列でカーソル位置や文字色などを制御することができます。
この際、Windowsバッチでは、ESC文字をどうやって出力するかが問題となります。
今回は prompt命令が$Eという表現でESC文字を出力できることを利用しています。
以下の行で 変数ESCに格納し、その後はこれを %ESC% という表現で使いまわします。
for /f %%a in ('"prompt $E& echo. |cmd /k"') do (set ESC=%%a)
このほかに次の別解もあります。
for /f "usebackq" %%a in (`Powershell -command "$esc=[char]0x1b;Write-Host ${esc}"`) do (set ESC=%%a)
各進捗表示は、こんな感じの組み合わせです。
echo ++________ 20%% %ESC%[1A
timeout 1 >NUL
進捗率の数字の%は、変数を示す%と区別するために、%%という表現でエスケープします。
ESC[1A は1行上に移動を意味します。
1行上に移動しますが、echo命令が自動的に改行するので、結果として同じ行にとどまります。今回のポイントはここです。
その後、遅い処理をしていることをイメージして、1秒待機しています。
本来ですと、ここになりかやりたい処理がくるのだと思います。
最後のところで、最初に出した「処理を実行しています」を「処理が完了しました」に上書きしています。
ESC[1Aで カーソルを1行上に移動して、ESC[1M でその行の表示をクリアしています。
そのあと、処理が完了しました。 を表示することで、上書きを実現しています。
最後にESC[1B で次の行、つまり ++++の行に移動し ESC[1M で表示クリア そして ESC[1A で前の行、つまり 処理が完了しました の行に戻ります。
そのあと、ECHOが自動的に改行するので、結果として、++++の行にカーソルはとどまり、ここに pause命令のメッセージが表示されます。