*LT会での発表を記事化しています*
本編
みなさん、PCのOSは何を使っていますか?うんうん。やっぱり、"Ubuntu"ですよね!と、言うわけで、今日はubuntuのセットアップスクリプトを書いた話をしたいと思います。 Ubuntuを使っている皆様は、きっとこう思ったことがあると思います。
- ”あー、OSクリーンインストールしてー。”
- ”けどセットアップだりーなー”、と。
そんなあなたに朗報です! 今日はUbuntuのセットアップを簡単にする、セットアップスクリプトを紹介します。
https://github.com/HBenpitsu/bokuga-kangaeta-saikyo-no-ubuntu-setup-scripts Ubuntuで使える環境構築の手段といえば、AnsibleやSingularityがありますが、調べたところ大量のPCをセットアップするのに向いており、Singularityはコンテナを扱うものだということです。 個人にはちょっとオーバースペックですね。 そこで、今回は慣れ親しんだBashScriptによってセットアップ用のスクリプトを作ってみました。決して勉強するのが面倒くさかったとかそういうことじゃないですよ。ほんとです。 最初からコンテナを活用すれば環境が汚れなくて済むじゃないかという声も聞こえてくるようですが、そういう意見には蓋をしておきましょう。 といっても、実は作ったのは単一のスクリプトファイルではありません。 ひとまず、ディレクトリの構成を見てみましょう。
セットアップを開始する際にはSETUP.shを実行すればほぼ自動でセット アップが完了するという算段です。 すべてのセットアップ手順をSETUP.shに書き込まずに、こうしてファイルを分離したのには意味があります。核となるアイデアを2つ順に見ていきましょう。
アイデア1
1つ目のアイデアは各セットアップの処理を外部のファイルに分離し、数字、アンダーバー、名前、のような命名規則を与えることです。これによって、それぞれのスクリプトが短くなり保守性が向上する上に、実行順の制御や拡張が容易になります。 あまりに長いスクリプトはどこになんの処理が書いてあるか探すだけで一苦労ですが、こうやってファイルを分けておけば一瞬で見つけられます。 しかも命名規則を工夫することによって実行順の制御がメチャクチャ簡単に!ファイル内でカット・アンド・ペーストをする必要はありません。
アイデア2
2つ目のアイデアはフェーズシステムです。 インストールしたいものの中には、一度再起動しないと後の作業ができなくなってしまうものもあることでしょう。 gnome-extensionsとかgnome-extensionsとかgnome-extensionsとかのことです。 一つのスクリプトファイルでは再起動後に自動起動して、進行状況を自動で復元して途中から再開する、という曲芸はきっと可能でしょうが、不必要に複雑になります。 しかし、ファイルを分離したことによって容易にフェーズシステムを導入することができました。 フェーズシステムというのはSETUP.shとphase1,2,3とかいうディレクトリたち、そしてcurrent-phaseというファイルで成り立っています。 およそ想像はつくでしょうが、再起動後の自動起動と進行状況の復元を実現するものです。 進行状況の復元は簡単ですね。current-phaseに記録されたフェーズを読み出せば良いだけです。 自動起動もタスクの一つである99_phase-terminatorで実現しています。この辺は後で見ることとして。。。 なにはともあれ、これによって、私達はたまにパスワードを入力するだけで、あとはコーヒーをすすりながら待っているだけでセットアップが完了するのです!
ディレクトリ
コアアイデアの説明が終わったところで、ディレクトリ構成を見直してみましょう。
なにやらsrcとかtasksとかいう不審なディレクトリがありますね このsrcというのは、セットアップに必要なファイルをおいておく場所です。 tasksは中にフェーズの名前のディレクトリがありますが、基本的に実際にインストール処理を行うスクリプト (タスク) を配置する場所です。 このように分けておくと整理されてる感じで見通しが良くなりますね! こういう構成にしておくことで、SETUP.shはディレクトリの中にあるタスクを片っ端から実行するだけで良くなるので、プログラムも簡便になります。
スクリプトの作り方
SETUP.shの中身もかんたんなので軽く見てみましょう。
OS_SETUP_DIR=$( cd $(dirname ${BASH_SOURCE:-$0}); pwd )
export OS_SETUP_DIR
CURRENT_PHASE=`cat $OS_SETUP_DIR/tasks/current-phase`
if [ "$1" = "" ]; then
echo [msg] press Enter-key to continue
read
chmod +x $OS_SETUP_DIR/tasks/$CURRENT_PHASE/*
for task in `ls $OS_SETUP_DIR/tasks/$CURRENT_PHASE`; do
echo === === start: $task === ===
$OS_SETUP_DIR/tasks/$CURRENT_PHASE/$task
done
fi
if [ "$1" = "list" ]; then
for phase in `ls $OS_SETUP_DIR/tasks`; do
if [ -d $OS_SETUP_DIR/tasks/$phase ] ; then
for task in `ls $OS_SETUP_DIR/tasks/$phase`; do
echo $phase/$task
done
fi
done
fi
if [ "$1" = "exec" ]; then
chmod +x $OS_SETUP_DIR/tasks/$2
$OS_SETUP_DIR/tasks/$2
fi
if [ "$1" = "phase" ]; then
echo $2 > $OS_SETUP_DIR/tasks/current-phase
fi
一番難しいのは一番上の行ですかね。 $()で囲ってあげると、内容を先に実行させて、その結果を使えるんですね。``でもいいのですが、ダラー括弧だと入れ子にできるんですね。 スクリプトファイルが置いてあるディレクトリを取得するワンラインになってます。 ${BASH_SOURCE:-$0}というのはなんだかよくわかりませんが、それの0番目にソースファイルのパスがはいっているんですね。そしてdirnameでそのディレクトリを取得して、そのままだと相対パスになっているかも知れないので、 cdとpwdで絶対パスに直しているわけです。 あとは見慣れた制御構文ですかね。第一引数や第二引数の値はダラー1とかダラー2とかで見ることができるので、それで条件分岐させています。何も渡さずに実行すればセットアップが始まりますし、listと付けてやればタスクの一覧を表示してexecとタスクのファイル名を入れてやるとそれだけ実行してくれます。 直接実行すればいいじゃん、とも思うかもですが、OS_SETUP_DIR変数を使っているとちょっと厄介なので、SETUP.shから呼び出せるようにしました。 あとは、phaseを渡すと現在のフェーズの書き換えができるようにしています。使わないですけどね。
タスクの詳細を見てみよう
つぎにそれぞれのタスクたちの詳細を見てみます。 例えば自動再起動はタスクの一つ、フェーズターミネータで実現しています。 実際どんなスクリプトなのかちょっと覗いてみましょう
echo === terminating phase1 ===
cp $OS_SETUP_DIR/src/setup-autostarter.desktop ~/.config/autostart
echo "Exec=bash -c '$OS_SETUP_DIR/SETUP.sh'" >> ~/.config/autostart/setup-autostarter.desktop
echo phase2 > $OS_SETUP_DIR/tasks/current-phase
echo Press Enter-key to reboot
read
sudo reboot
こんな感じ。 ダラーOS_SETUP_DIRはSETUP.shで設定、exportした変数です。 キモは2行目のファイルコピーと3行目のecho execなんたらかんたらですね。 実はubuntuでスクリプトの自動起動をさせるのは簡単で、 ホーム、ドットコンフィグ、オートスタート下にデスクトップエントリーファイルを設置するだけで良いのです。 あとは進行状況を記録するcurrent-phaseファイルに次のフェーズを書き込んだら後は再起動するだけです。 急に再起動されると困るので、readで一度ユーザーの入力を待っています。
echo === terminating phase1 ===
echo phase3 > $OS_SETUP_DIR/tasks/current-phase
echo Press Enter-key to reboot
read
sudo reboot
次にフェーズ2. まぁやっていることはフェーズの書き換えだけですね。gnome-extensionsとかいうやつは二回も再起動しないとインストールできないので・・・
echo === terminating phase1 ===
echo done > $OS_SETUP_DIR/tasks/current-phase
rm -f ~/.config/autostart/setup-autostarter.desktop
そして最後のフェーズ。コンフィグ、オートスタートからさっき追加したデスクトップエントリを消せば、立つ鳥跡を濁さずです。
そのほか
他にも、IMEの設定の復帰などでちょっと困ったりもしましたが、ホームディレクトリの.configから今の設定をコピーしてきて、初期化時にはそいつを貼り付けちゃえばオッケー。 なんだか力技な気もしますがこれでできるからいいのです。 と、タスクはこんな感じです。他にも色々タスクはありますが、まぁ見たままって感じです。
終わりに
Ubuntuはこんなにも拡張性に優れ、デベロッパーフレンドリーでユーザーフレンドリーなOSです! windowsなんか使っている人はそんなOSかなぐり捨ててUbuntuを使いましょう。(冗談です)