dotfilesのsetup用スクリプトを書いた
はじめに
今更...な記事ですが github で dotfiles を管理しています。今まで個別にシンボリックリンクを張ったりしていたのですが、シェルスクリプトで纏めたいと思ったのがいつの間にか沼へずぶずぶ。
目次です。
dotfilesとは
Windows派にはあまり馴染みのない言葉ですが、dotfiles
とは Linux や MacOS における設定ファイルの事です。大学1年のに Linux のリテラシー演習にて、ホームディレクトリにあったログインシェルの.bashrc
を弄り倒したのがきっかけで「設定書くのが楽しいっ!!!!」となりました。高まる Windows はクソという感情も最近はWSLによって緩和されつつあります...
きっかけ
自宅の仮想環境や大学の演習端末、OSを吹き飛ばす度に自分好みの開発環境まで一括設定するスクリプトの必要性を感じ始めました。特に、ラップトップの代替わりや HDD or SSD 故障時のスムーズな移行のためにもdotfilesの管理はおすすすめです。理想的な機能はこんな感じ。
- 秘伝のタレたる
.dotfiles
を適所に配置するシンボリックリンク - OS 毎に足りないパッケージをインストール
- 対話処理: インストールの必要性を最初に確認(yes/no)
github で設定ファイルをどうやって管理するの?という人は、先人の知恵がはてなブログや Qiita に溢れているのでそちらを参照してください。では以下がスクリプトの解説です。
setup.sh の中身
端末にセットアップ状況を表示するためにちょっとコードが長くなってますが、大まかな記述の流れは、
インストールパスの設定
標準出力の装飾設定
関数定義
OSで条件分岐して必要パッケージがない場合はインストール
シンボリックリンクをドヴァァッ
こんな感じです。リポジトリのれあどめにも書いてますが、curl
が事前にインスト―ルされていればワンライナーで楽にインストールが可能です。自分のターミナル上で
$ bash -c "`curl -fsSL https://raw.githubusercontent.com/takuzoo3868/dotfiles/master/setup.sh `"
と打ち込むと、わざわざリポジトリをgit clone
しなくても実行してくれます。シェル芸ですね。homebrew のインストール方法を流用した形になります。bash -c
は直後の文字列を命令として読み込むためのオプションです。これによりcurl
でsetup.sh
の中身を取得すれば実行できるという訳です。curl
側のオプションはこんな事をしています。
-f, --fail: サーバーエラーが起こった時に何も出力しないで終了 -s, --silent: silentモードとなり進行状況を出力をしない -S: --show-error: silentモードと同時使用でエラーのみ表示 -L: --location: ページがリダイレクトされてる場合にはリダイレクト先まで取得しにいく
読み込みエラー防止のためのオプションと捉えて間違いないかと思います*1。
文字色の設定
# use colors on terminal tput=$(which tput) if [ -n "$tput" ]; then ncolors=$($tput colors) fi if [ -t 1 ] && [ -n "$ncolors" ] && [ "$ncolors" -ge 8 ]; then RED="$(tput setaf 1)" GREEN="$(tput setaf 2)" YELLOW="$(tput setaf 3)" BLUE="$(tput setaf 4)" BOLD="$(tput bold)" NORMAL="$(tput sgr0)" else RED="" GREEN="" YELLOW="" BLUE="" BOLD="" NORMAL="" fi
一番最初に困ったのは、echo -e
による文字色の出力について escape sequence が効かない状況でした。シェル環境によって、或いは shebang が#!/bin/sh
の時などはPOSIXが有効なのでecho
も機能が制限されます*2。故に escape sequence を書いてもそのまま端末に表示されちゃいます。printf
を使うと解決できたりしますが escape sequence が途中でよく分からなくなってしまうので、ここでは便利なtput
を活用します。tput
とは escape sequence とターミナル機能の関連付けなどが定義されたterminfo
を利用して、依存情報をシェルでも使えるようしてくれる優れたコマンドです。setaf
で指定した色番号に文字色を変更できます。bold
は太字化、sgr0
は文字装飾をリセットして標準に戻します。スクリプトでは上記のように文字色を変数定義した上で、文字出力を以下のように区別する事にしました。
# info: output terminal green info() { printf "${GREEN}" echo -n " info " printf "${NORMAL}" echo "$1" } # error: output terminal red error() { printf "${RED}" echo -n " error " printf "${NORMAL}" echo "$1" } # warn: output terminal yellow warn() { printf "${YELLOW}" echo -n " warn " printf "${NORMAL}" echo "$1" } # log: out put termial normal log() { echo " $1" }
info: 正常な進行状態、進捗を表示
error: 異常終了するときやエラーメッセージの表示
warn: ユーザーの同意が必要な警告表示
log: 色なんて要らねぇ、ただ表示しろ用
この辺の考え方はCUIベースのOSSにも応用できそうな気がしますがどうなんでしょう。自分はbio/AA芸人だと思ってるのでdotfilesにもAAを入れました。先ほどのワンライナーコマンドを叩くとこんな感じで表示されます。
対話応答
read -p "$(warn '(U^w^) < Are you sure you want to install it? [y/N] ')" -n 1 -r if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "" error 'Installation failed. Nothing changed.' exit 1 fi echo "" info "Start install the dotfiles."
本当に実行しちゃっていいの?みたいな確認は必要ですよね。シェルスクリプトの場合はread
で実装できます。入力待ちにおける yse/no の判断は以下のオプションを使用しました。
-p: プロンプト表示、入力待ち状態となる -n: 引数に入力する文字数の指定 -r: エスケープの無効化
デフォルトではY
かy
以外の入力があった場合、異常終了するように処理しています。よってそのままEnter
を押してもn
と解釈されるので異常終了します。一方、条件に当てはまらない場合はそのままインストール処理へ移行します。
OSの条件分岐
以前UNIX系統のディストリビューション判定のスクリプトを書いたのでそれを流用しました。
## Android if [ $(uname -o) = "Android" ]; then # ... elif [[ $(uname) = "Linux" ]]; then ## Arch Linux if [ -f /etc/arch-release ]; then # ... ## Ubuntu / Debian elif [ -f /etc/debian_version ] || [ -f /etc/debian_release ]; then # ... fi ## MacOS elif [[ $(uname) = "Darwin" ]]; then # ... else # F0ck wind0ws. G0 t0 he11! error "Your platform ($(uname -a)) is not supported." exit 1 fi
基本的にuname
コマンドで対応できますが、Linuxのディストリビューションの違いは/etc/hogehoge-release
を参照する必要があります。この辺の処理部分の記述は無駄が多いのでまだまだ改善の余地がありそうです。今は自分が触ってるOSだけ条件式に追加していますので、他のディストリビューションの場合はerror
を表示して異常終了します。一応、 Termux on Android にも対応させるつもりで書いてますが、アレは特殊な環境なので shebang をどうにかしないと何とも言えない感じですね...。
おわりに
たかがdotfiles
のインストールかもしれませんが、設定すると結構奥が深いです。完全にシェル沼です。今後の課題としては OS 毎のインストール記述が煩雑になってきたので別のスクリプトで管理しようかと考えています。現状はシンボリックリンクも強制的に貼り付けなので、バックアップファイルを作成して元々あるdotfiles
を一時退避させる必要もあると思います。あとは、MacOS の記述が手元に MacMini を置いていた時のものなので改善できそうな気がします...。今度はneovimやgitの設定を記事に書いて晒します()