Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2863

Bashでインストーラーのが動くやつを作る

$
0
0

このスクリプトの解説です。

最初の部分

bash test.bash >/dev/null 2>&1 & #子スクリプトの実行
id=$! #子スクリプトのpidを取得

">/dev/null/ 2>&1"で子スクリプトの実行しているものをこちらで表示しないようにしています。
"$!"は直前のpidをの値が代入されます。それを"id"に代入しています。pidは子スクリプトの終了を感知するのに使います。

子スクリプトの実行するところの最後に"&"をつけている理由

プログラムは上から下へ実行されていきます。これは、bashのスクリプトも例外ではありません。プログラムは基本的には前の動作が終わらない限り、次の動作には移りません。このスクリプトの場合、子スクリプトが終わるまで、次の動作には移れないのです。これはインストーラーとしては致命的です。しかし、bashでは最後に"&"をつけるだけで次の動作に移ることができます。

名前等の定義

name="テスト" #名前の定義
action="テスト" #アクションの名前を定義
name_size=$(printf "$name" | wc -c) #名前のサイズを取得
action_size=$(printf "$action" | wc -c) #アクションの名前のサイズを取得

#名前が日本語か判断
#名前の先頭がaからzまたはAからZでなければ"name_size"の再定義
if [[ ! $(echo $name | head -c1) == [a-z] ]] ||  [[ ! $(echo $name | head -c1) == [A-Z] ]]
then
    name_size="$(($name_size-$(($name_size/3))))" |
fi

#アクションの名前が日本語か判断
#アクションの名前の先頭がaからzまたはAからZでなければ"action_size"の再定義
if [[ ! $(echo $action | head -c1 ) == [a-z] ]] || [[ ! $(echo $action | head -c1 ) == [A-Z] ]]
then
    action_size="$(($action_size-$(($action_size/3))))"
fi

日本語か判断する理由

日本語か判断しているところをコメントアウト(先頭に"#"をつける)して実行すると、

コメントアウトしていないもの:テスト [テスト] [<==>                                                          ]
コメントアウトしたもの   :テスト [テスト] [<==>                                                    ]

長さが変わりました。
日本語の表示にはUTF-8ってやつが絡んでくるですが"a"と"あ"じゃ文字の大きさが微妙に変わってきます。そのせいなのかわからないのですが、日本語だとこういうことが起きてしまいます。なので日本語かどうか判断しています。

ウィンドウのサイズの取得等

# ウィンドウのサイズを取得
window_size=$(resize | grep "COLUMNS=" | grep -oP "[1-9][0-9]*")
# バーの長さを決定
if [ $window_size -gt 100 ]
then
    bar="<======>"
elif [ $window_size -gt 80 ]
then
    bar="<====>"
elif [ $window_size -gt 50 ]
then
    bar="<==>"
else
    bar="<>"
fi

とくに言うことはないです。"resize"を実行したときに出る表示を"grep"で取得しているだけです。

バー関連

bar_tail="$(printf "$bar" | tail -c1)" #バーの最後、今回は">"を取得
bar_head="$(printf "$bar" | head -c1)" #バーの先頭、今回は"<"を取得
bar_size="$(printf "$bar" | wc -c)" #バーのサイズを取得
list="$(printf "$bar""$(printf "%0*d\n" $(($window_size-$name_size-$bar_size-$action_size-6)) | sed 's/0/ /g')\n")"

最後の行の解説

#これで必要な空白の数を計算
#その1 $(($window_size-$name_size-$bar_size-$action_size-6)) 
#バーと必要な空白を表示
#その2 printf "$bar""$(printf "%0*d\n" #その1 | sed 's/0/ /g')\n"

そして、#その2を"list"に代入しています。

表示

mode="1" #バーが左から右に移動
while : #無限ループ
do
  sleep 0.01
  #上書き表示
  printf "$action [$name] [$list]\r"
  #子プロセスが終了したらループを抜ける
  if [ -z "$(ps $id | grep -v "PID")" ]
  then
      break 2
  fi
  if [ "$mode" = "1" ]
  then
      #バー[] => []バー みたいな感じで置き換えているだけです。
      list="$(printf "$list" | sed 's/'$bar' / '$bar'/g')"
      #バーが右端に来る、今回は"==>]"こうなったらモードが2になります。
      if [ "$(printf "[$list]" | tail -c2)" == "$bar_tail]" ]
      then
          mode="2" #バーが右から左に移動
      fi
  else
      #[]バー => バー[] みたいな感じで置き換えているだけです。
      list="$(printf "$list" | sed 's/ '$bar'/'$bar' /g')"
      #バーが左端に来る、今回は"[<=="こうなったらモードが1になります。
      if [ "$(printf "[$list]" | head -c2)" == "[$bar_head" ]
      then
          mode="1"
      fi
  fi
done
echo -e "\n終了しました。" #バーなどとかぶらないように改行して表示しています。

最後に

分からないところがあったらtwitterにDMください。


Viewing all articles
Browse latest Browse all 2863

Trending Articles