プログラミングを学習の皆さん、ターミナルをよく使いますよね?
プログラミング学習を始めたての頃は、「なんかターミナルって難しそう」、「ターミナルって英語表示だから使うのに抵抗がある」
なんて思ったことないですか?ちなみに僕はターミナルに抵抗がありました。
そんな気持ちを持っている方のために、ターミナルを使うのが楽しくなるプログラムを紹介したいと思います。
今回は、シェルスクリプトと呼ばれる言語を使って、プログレスバーを作っていきます!
シェルスクリプトって初めて聞いたよ、知らないよって人も安心してください。わかりやすく説明してあるので、気楽に読み進めていってください。
シェルスクリプトとは?
今回、シェルスクリプトという言語を使ってプログレスバーを作成していきます。
シェルスクリプトとは、シェルに実行してほしいことを伝えるプログラムです。シェルスクリプトを使用することで、複数のコマンドを実行することができ、作業の効率化が見込めます。
シェルは、ターミナルの裏側で動いているコンピュータと人間を繋ぐ役割をしてくれる方だと思ってください。人間側が「コンピュータよhitori.txtというファイルを作成せよ!」って言えば、コンピュータが日本語をそのまま理解して動いてくれる、、、なんてことはないですよね。
シェルは人間の言葉をコンピュータが理解できるように翻訳してくれます(厳密には違うが)。
シェルスクリプトはこのシェルに人間側がしたいことをまとめたファイルのことです。
プログレスバーを作ってみよう!
早速、プログレスバーを作っていこうと思います!
完成すると以下のようになります。
では作っていきましょう!
以下が今回作成するプログラムです。これをコピーして、 拡張子が.shのファイルにペーストすればzsh ファイル名
で利用できます。
#!/usr/bin/env bash if [[ $# -eq 0 ]];then timer=500 elif [[ $# -eq 1 ]];then timer=$1 else echo "Usage: ./progress_bar.sh [time]" exit 1 fi echo "約$((${timer}/100))秒間かかります。終了したいときはCtrl+c" trap 'echo -n -e "\033[?25h"; exit $STATUS' SIGINT echo -n $'\033[?25l'; for i in $(seq $timer); do sleep 0.01; if [[ $(($i%10)) -ne 0 ]]; then echo -n $'\b'; fi echo -n -e "\U$(printf "%X" 0x258B )"; done echo $'\033[?25h';
では、このコードについて解説していきます。
まず一行目の#!/usr/bin/env bash
はシバン呼ばれる記述です。PythonやRubyを学習したことある方はコメント?と思うかもしれませんが、コメントとは少し違います。コメントは実行するときは影響のないものですが、シバンは影響を及ぼす場合があります。
シバンとはLinuxなどのUNIX系OSでインタプリタを指定するために必要な記述です。インタプリタは人間の書いた高級言語を逐次機械語に翻訳して実行することです。
UNIX系OSで必要な記述なのでWindowsの方は必要ありません。筆者はMacを使用しているので必要です。
if [[ $# -eq 0 ]];then timer=500 elif [[ $# -eq 1 ]];then timer=$1 else echo "Usage: ./progress_bar.sh [time]" exit 1 fi
上記のコードは使い方に関する記述です。今回は2つの利用パターンにしてあります。
- コマンドライン引数になにも入力されなかった時、5秒間のプログレスバーにする
- コマンドライン引数に時間を指定した場合、その時間のプログレスバーにする
コマンドライン引数とは実行時に指定した引数のことです。例えば、./sample.sh 2
とコマンドラインで実行した時は、2
がコマンドライン引数となります。複数指定することが可能で、./sample 2 many hitori
と実行したときは、2
、many
、hitori
の3つがコマンドライン引数になります。
今回は引数がない場合、1つある場合、2つ以上の場合で処理を分けます。
シェルスクリプトでのif文は
if [[ ]]; then #コードを記入 elif [[ ]]; then #[[ ]]の中の単語は左右に空白を入れること else #最後にfiを書くこと fi
このようになります。少し独特ですが、if, else, elifと見慣れたところもあります。
if [[ $# -eq 0 ]];then
、これはコマンドライン引数が0個だったら、という処理を行います。[[ ]]
は他の言語でいうところのカッコ()に当たります。
$#
はコマンドライン引数の個数を、-eq
はequalということで等しい==を表します。よって、if [[ $# -eq 0 ]];then
は「もしコマンドライン引数の個数($#
)が0に等し(-eq)かったら」ということになります。
そして次の行ではtimerという変数に500を代入しています。timerに代入された値はtimer/100
秒間のプログレスバーを作るという意味です。ここでは500を代入しているため、5秒間のプログレスバーになります。
ここで気をつけなければいけないのが=の左右です。よくプログラムを書くとき、=の左右に半角スペースを入れる人がいますが、シェルスクリプトでそれをやるとエラーになります。絶対に=の左右に半角スペースを入れないようにしてください。
else文で実行されるecho "Usage: ./progress_bar.sh [time]"
とexit 1
は今回の仕様に合わないときは使い方を出力して、終了ステータスを1にして終了するということです。
echo "出力したい文章"
でターミナル上に文章を出力できます。
trap 'echo -n -e "\033[?25h"; exit $STATUS' SIGINT
これはCtrl+cで終了させたときの処理を書いています。”\033[?25h”は以降に説明します。
echo -n $'\033[?25l'; for i in $(seq $timer); do sleep 0.01; if [[ $(($i%10)) -ne 0 ]]; then echo -n $'\b'; fi echo -n -e "\U$(printf "%X" 0x258B )"; done echo $'\033[?25h';
これがこのスクリプトのメインです!
最初のecho -n $'\033[?25l';
はターミナル上のカーソルを非表示にします。\033[?25lはエスケープシーケンスと呼ばれる特殊な文字列です。これでカーソルが非表示になります。
カーソルを非表示にすることでプログレスバーっぽくなります。ここ重要!
プログラムが終了したらカーソルは再度表示させたいため、最後の行echo $'\033[?25h';
で一通り処理が終わったらカーソルを表示させます。
for i in $(seq $timer); do sleep 0.01; if [[ $(($i%10)) -ne 0 ]]; then echo -n $'\b'; fi echo -n -e "\U$(printf "%X" 0x258B )"; done
for文はPythonやRubyに似ています。最後にdoneを書くことを忘れないようにしましょう。
seqはコマンドです。seq 整数
とすることで1から指定した整数までの連続した整数を返します。
$(コマンド
)はカッコの中のコマンドを実行して得られた結果を使用するということです。
つまりtimer変数に500が代入されていたとして、$(seq $timer)
は1,2,3,…,498,499,500ということになります。
したがって、for i in $(seq $timer)
はこの連続する整数を一つずつ変数iに入れてfor文の中身を実行します、ということになります。
そして、for文の中身について
sleep 秒数
でその時間分、実行が止まります。今回はsleep 0.01
ですから、0.01秒間プログラムを止めています。プログラムをsleepコマンドで止めないと一瞬で出力されてプログレスバーになりません。プログレスバーにするために、プログラムを止めてそれっぽくしましょう。
その後、塗りつぶされた長方形を出力しています。こんなやつ∎(文字化けしないでお願い)
これで完成です!!10秒間のプログレスバーを実行したいときはzsh ./ファイル名 1000
としましょう。
コマンドライン引数が1つであるため、timerに1000が代入され、(1000 / 100)秒間のプログレスバーが実行されます。ただし、これは厳密に10秒間というわけではないです。正確さにかけるので、あくまでお遊びということで。
おわりに
今回はシェルスクリプトを使ってプログレスバーを制作してみました。
シンプルですが地味に面白いですよね〜。∎(塗りつぶされた長方形)を#にすると違ったバーを楽しめます。
また、出力する際の色を変更してみても面白いです(面倒でやりませんでした)。
お疲れ様でした〜それではまた違う記事で会いましょう!
コメント