ゆっくり開発

開発したい時に開発するブログ

ドットファイルの install/uninstall スクリプトの作成

クラウドを利用したドットファイルの共有

複数の環境(パソコン)間でドットファイルを共有するために,クラウドを利用すると便利である. このため,最近,ドットファイルの管理にクラウドを導入した.
また,クラウド環境として自分はGitHubを採用した.

ドットファイルの install スクリプトの作成

インストールの手間を短縮

新しい環境を使い始める際や既存の環境をリセットした際の, ドットファイルをインストールする手間を短縮したい. このため,今回はインストールスクリプトを作成する.

インストールスクリプトの設計方針

GitHubで知り合いのリポジトリを漁っていると,以下のコードが釣れた.

#!/bin/bash

for f in .??*
do
    [[ "$f" == ".git" ]] && continue
    [[ "$f" == ".DS_Store" ]] && continue
    ln -s $HOME/dotfiles/$f $HOME/$f
done

上記コードはホームディレクトリにドットファイルのリンクを貼るスクリプトである.このコードを拡張し,インストールスクリプトを作成することにした.

達成したい課題

  1. MacとWSL(Windows)で実行可能
    現状,MacとWSLのターミナルを使っているので, どちらからでも実行できるようにする.
  2. MacとWSLでインストールするドットファイルを変更
    ターミナルが異なる場合,共有したいドットファイルもあれば,共有したくない(異なる環境設定にしたい)ものもある. このため,異なるターミナル,今回はMacとWSLでインストールするドットファイルを変更する.
  3. リンクが貼れない状況に対応
    貼りたいドットファイルと同名のファイルが既にホームディレクトリに存在する場合,$ lnコマンドにエラーを出力させず,自分が設定した文字列を出力する(エラー処理).

各課題への対処

MacとWSL(Windows)で実行可能

Macで実行できたコードがWSLで動かない,といったことは何度もあったが,正直,原因がよくわからなかった. 色々試した結果,以下の3点を行うことでうまく動いた.

  • functionを使わない.
    WSLの方でエラーを吐かれた.このため,functionを使わず,代わりに別ファイルを作成し,そのファイル(スクリプト)を呼び出すことにした.
  • bashではなく,shで実行する.
    shebangbashからshに変えるだけでなく,以下の様に実行コマンドもshを使う.
    $ sh ./install.sh
  • 条件式に[[を使わず,全て[を使う.
    [[bashのコマンドらしいので,[に変更する.
MacとWSLでインストールするドットファイルを変更

以下の方法で対処する.

以下のコードで実行OS(ターミナル)を判断し,ホームディレクトリに共有ドットファイルと専用ドットファイルのリンクを貼る.

#!/bin/sh

# OS(ターミナル)の種類を判断
if [ "$(uname)" = 'Darwin' ]; then
  OS='Mac'
elif [ $(echo $(uname -r) | grep -e 'Microsoft') ]; then
  OS='WSL'
else
  echo "Your platform ($(uname -a)) is not supported."
  OS='undefined'
fi
echo $OS' terminal\n'

# 各OS(ターミナル)に応じて dotfile のリンクを貼る.
if [ ! $OS = "undefined" ]; then
  sh scripts/link_dotfiles_to_home.sh $OS"/"
fi

# 各OS(ターミナル)共通の dotfile のリンクを貼る.
sh scripts/link_dotfiles_to_home.sh ""

また,link_dotfiles_to_home.shは指定したディレクトリ下のドットファイルのリンクをホームディレクトリに貼るスクリプトである. 第一引数でそのディレクトリを指定する.
これは参考コードのfor f in .??*for f in $1.??*に改変することで実現した.

リンクが貼れない状況に対応

以下の状況を条件文により分岐し,処理.

  • 既にファイルがある場合
    [NG] を出力
  • 既にリンクがある場合
    [skip] を出力
  • それ以外(リンクが貼れる場合)
    リンクを貼り,[OK] を出力

また,各[NG], [skip] および [OK] のecho出力には色を付けた.
link_dotfiles_to_home.shソースコードは以下の通り.

#!/bin/sh

for f in $1.??*
do
  # ファイルの絶対パスを取得
  dotfile_path=$HOME"/dotfiles/"$f
  # ファイルパスの一番右の"/"以降の文字列を取得
  dotfile_name=${dotfile_path##*/}

  # 特定のファイルは pass
  [ "$dotfile_name" = ".git" ] && continue
  [ "$dotfile_name" = ".gitignore" ] && continue
  [ "$dotfile_name" = ".DS_Store" ] && continue

  # ファイルのリンクが既に貼られていれば skip を出力
  if [ -h $HOME"/"$dotfile_name ]; then
    echo "[\033[36mskip\033[0m] "$dotfile_name
  # ファイルの実体(!=リンク)があれば,NG を出力
  elif [ -e $HOME"/"$dotfile_name ]; then
    echo "[\033[31mNG\033[0m] "$dotfile_name
  # ファイルのリンクが貼られていなければ,シンボリックリンクを貼る.
  else
    ln -s $dotfile_path $HOME"/"$dotfile_name
    echo "[\033[32mOK\033[0m] "$dotfile_name
  fi
done

install スクリプトの実行による出力は以下の通り.

f:id:uttnaoki:20180627235523p:plain:w200f:id:uttnaoki:20180627235529p:plain:w200
dotfiles_install_fig

uninstall スクリプトの作成

処理内容はほぼ install スクリプトと同じで,作成されたリンクをアンリンクするだけ. 具体的に,link_dotfiles_to_home.shのソースの一部を以下のコードに改変し,delete_symbolic_links.shとして保存する. uninstall.shinstall.shlink_dotfiles_to_home.shを呼ぶコードをdelete_symbolic_links.shを呼ぶコードに変えるだけ.

#!/bin/sh

for f in $1.??*
do
  # ファイルの絶対パスを取得
  dotfile_path=$HOME/dotfiles/$f
  # ファイルパスの一番右の"/"以降の文字列を取得
  dotfile_name=${dotfile_path##*/}

  # 特定のファイルは pass
  [ "$dotfile_name" = ".git" ] && continue
  [ "$dotfile_name" = ".gitignore" ] && continue
  [ "$dotfile_name" = ".DS_Store" ] && continue

  # ファイルのリンクが既に貼られていれば,ホームディレクトリのリンクを削除
  if [ -h $HOME"/"$dotfile_name ]; then
    unlink $HOME"/"$dotfile_name
    echo "[\033[32mOK\033[0m] "$dotfile_name
  # ファイルの実体(!=リンク)があれば,NG を出力
  elif [ -e $HOME"/"$dotfile_name ]; then
    echo "[\033[31mNG\033[0m] "$dotfile_name
  # ファイルのリンクが貼られていなければ skip
  else
    echo "[\033[36mskip\033[0m] "$dotfile_name
  fi
done