Bashシェルスクリプトで簡易なプログレスバーを実装する

Bash

はじめに

printf コマンドとエスケープシーケンスを組み合わせてかんたんなプログレスバーを実装する方法について紹介します。

検証環境

$ uname -moi
x86_64 MacBookPro16,1 Darwin

$ bash -version | head -n 1
GNU bash, バージョン 5.0.18(1)-release (x86_64-apple-darwin19.5.0)

プログレスバーを実装したい

シェルスクリプトを組む場合、多くは作業の自動化を目的としていて、なるべくインタラクティブな手続きが介入しないようにすると思います。

対して、時間のかかる処理を実行しておき、その間にのんびりお茶を飲む、といった場合にシェルスクリプトが活躍する場合もあります。

時間がかかる処理をシェルスクリプトで実装した場合、どこまで処理が進行したのかわかるようにかんたんなプログレスバーを実装してみましょう。

必要なもの

準備するようなものは特に入りません。
BashとLinuxのいくつかのコマンドが利用できれば実現可能です。

早速実装してみる

1秒ごとにスリープし、これを10回繰り返すようなかんたんな繰り返し処理を実装し、プログレスバーを表示させてみます。

実際のコードを見ながら解説していきます。

ソースコード ( show_progress_bar.sh )

#!/usr/bin/env bash

for I in {1..10}; do
  sleep 1
  # 進捗10%あたりドットを2つ ".." を出力
  BAR="$(yes . | head -n ${I} | tr -d '\n')"
  printf "\r[%3d/100] %s" $((I * 10)) ${BAR}
done
printf "\n"

実行結果

解説

ループ処理は 3行目から8行目 となります。

3行目 はループ開始です。
ここではループカウンタ I を1から10まで1ずつインクリメントして10回ループします。

4行目 は1秒ずつスリープさせるためのコマンドです。

5行目 はちょっと分かりにくいですね。これはプログレスバーをドット( . )を使って視覚化させるために .I 個連結した文字列を生成します。

6行目 ですべての情報を出力しています。
多くのプログラミング言語でもおなじみの printf を使っています。
%3d%s の部分にはそれぞれ printf コマンドの第二引数 $((I * 10)) 、第三引数 $(BAR) が埋め込まれます。

%3d は、数値を3文字幅で出力(不足分は左を半角スペースで埋める)するための設定です。

一番のポイントは \r です。
キャリッジリターン と言われる制御文字です。
出力内容をすでに出力済みの内容の先頭に戻します。

これによりループ時の出力内容は、前回の出力内容の先頭から上書きされます。

ひとこと

キャリッジリターンをうまく使うと、ちょっと変わった出力を行うことができますね。

Bash