今年も残りわずかになりましたね。年末年始のお休みを利用して、皆さんの設定ファイルを大掃除してみてはいかがですか?
ということで、今回は dotfiles のお話です。
私流の dotfiles のサンプルは https://github.com/Gandats/dotfiles-sample に置いてあります。
この記事を読まなくても、このサンプルの README.md を読んで、必要なファイルをコピーすれば便利に管理できるかもしれません。
dotfiles とは?
dotfiles とは、普段自分が使っているソフトウェアの設定ファイルを管理するリポジトリです。Unix系のOSでは設定ファイルは慣例的に . から始まる隠しファイル( .bashrc や .vimrc など)になっていることからこう呼ばれています。
これらをまとめてバージョン管理しておくことで、どこでも一瞬で自分好みの快適な環境を作り出せます!
ステップ1. dotfilesを始めよう
私流の dotfiles のサンプルは https://github.com/Gandats/dotfiles-sample に置いてあります。
まずは最小限の dotfiles
- GitHub で
dotfilesというリポジトリを作成 - 作成したリポジトリをホームディレクトリ直下に clone
- 各種設定ファイルをリポジトリ内にコピー (例:
mv ~/.bashrc ~/dotfiles/.bashrc) - もとの場所にシンボリックリンクを作成 (例:
ln -s ~/dotfiles/.bashrc ~/.bashrc) - コミット & プッシュ
- 新しい環境では clone してシンボリックリンクを作成
dotfiles で管理すべきものとそうでないもの
管理すべきものの例
- シェルの設定
-
.bashrc.bash_profile.zshrc.zshenv
-
- エディタの設定
-
.vimrc.emacs.d/init.el
-
- CLIツールの設定
-
.tmux.conf.tigrc
-
管理すべきでないものの例( .gitignore に追加する)
- 常に自動で更新されるファイル(履歴やキャッシュ等)
-
.bash_history.zsh_history.zcompcache.zcompdump.viminfo.emacs.d/history等
-
- バックアップファイル
-
*~*.swp等
-
- 環境に大きく依存する設定(参考: Tips)
- 環境変数
PATHやLD_LIBRARY_PATH等に明らかに環境固有の場所を追加するとき - CUDAの設定
- 環境変数
管理してはいけないものの例
- 認証情報が入ったディレクトリやファイル
-
.ssh.aws
-
ステップ2. 自動でシンボリックリンクを作成するスクリプトを書こう
私流の dotfiles のサンプルは https://github.com/Gandats/dotfiles-sample に置いてあります。
毎回、新しい環境でシンボリックリンクを作成し直すのは(特に設定ファイルが増えると)意外と大変です。
自動でシンボリックリンクを作成するスクリプトを書いてみましょう。
自動スクリプトを作成する
-
リポジトリ直下に
dotfilesというディレクトリを作って、設定ファイルをそこに移動してください。ターミナルにてcd <リポジトリのパス> mkdir dotfiles mv .* dotfiles -
リポジトリ直下に
scriptsディレクトリを作成し、そこにlink.shを作成。ターミナルにてmkdir scripts cd scripts touch link.sh -
link.shを編集link.sh#!/bin/sh dotfiles_root=$(cd $(dirname $0)/.. && pwd) # dotfilesディレクトリの中身のリンクをホームディレクトリ直下に作成 cd ${dotfiles_root}/dotfiles for file in .*; do ln -s ${PWD}/${file} ${HOME} done -
実行権限を付与
ターミナルにてchmod +x link.sh
これでターミナルで ./link.sh を実行するとシンボリックリンクが自動的に作成されるようになります。
このときのリポジトリのディレクトリ構造の例です。
├── .gitignore
├── dotfiles # 設定をまとめるディレクトリ
│ ├── .bashrc
│ ├── .vim
│ │ └── ...
│ └── .zshrc
└── scripts # リンク作成等のスクリプトをまとめるディレクトリ
└── link.sh # リンク作成スクリプト
ステップ3. どこでも動く dotfiles にしてみよう
私流の dotfiles のサンプルは https://github.com/Gandats/dotfiles-sample に置いてあります。
展開場所を考える
ステップ2で作成したスクリプトにはまだいくつかの問題点があります。
ケース1
neovim のように設定ファイルがホームディレクトリ直下でないソフトウェアに対応できない
- neovim の設定ファイルは
~/.config/nvim/init.vim
ケース2
VSCode のようにOSごとに設定ファイルの置き場所が異なるソフトウェアに対応できない
- Linux では
~/.config/Code/User/settings.json - macOS では
~/Library/ApplicationSupport/Code/User/settings.json
ケース1 任意の場所にシンボリックリンクを作成
ここでは、 dotfiles に linklist.txt を作成して、そこに展開場所を記述しましょう。
linklist.txt の書き方
- 各行は空白で区切られた2つのフィールド
- 1つめはターゲット(
dotfiles内のパス) - 2つめはリンクのパス
-
~や環境変数が利用可能
-
- 1つめはターゲット(
-
#以降や空行は無視される - 不要な設定は
script/link.shの実行前に#でコメントアウトすることでリンクが作成されない
# vim
.vim ${HOME}/.vim
# neovim
nvim ${HOME}/.config/nvim
# zsh
.zsh.d ${HOME}/.zsh.d
.zshenv ${HOME}/.zshenv
link.sh を修正
linklist.txt の内容を読むように link.sh の内容を修正しましょう。
# !/bin/sh
dotfiles_root=$(cd $(dirname $0)/.. && pwd)
# linklist.txtのコメントを削除
__remove_linklist_comment() {(
# '#'以降と空行を削除
sed -e 's/\s*#.*//' \
-e '/^\s*$/d' \
$1
)}
# シンボリックリンクを作成
cd ${dotfiles_root}/dotfiles
linklist="linklist.txt"
[ ! -r "$linklist" ] && return
__remove_linklist_comment "$linklist" | while read target link; do
# ~ や環境変数を展開
target=$(eval echo "${PWD}/${target}")
link=$(eval echo "${link}")
# シンボリックリンクを作成
mkdir -p $(dirname ${link})
ln -fsn ${target} ${link}
done
ケース2 OSごとにシンボリックリンクを切り替える
Unix系OSでは uname コマンドによってOSの名前( Linux Darwin FreeBSD 等)を取得できます。
ここでは、この値を利用してシンボリックリンクを切り替えてみましょう。
(より詳細に切り替えたい方は OSTYPE 環境変数などを利用しても良いかもしれません。)
linklist.txt をOSごとに作成
先程まで利用していた linklist.txt を以下のように変更します。(FreeBSD等に対応させる場合はLinuxやDarwinの部分を uname に置き換えてください。)
-
linklist.Unix.txt- Unix系OSに共通のもの依存しないもの(
~/.bashrcなど)
- Unix系OSに共通のもの依存しないもの(
-
linklist.Linux.txt- Linuxに固有のもの(
~/.config/Code/User/settings.jsonなど)
- Linuxに固有のもの(
-
linklist.Darwin.txt- macOSに固有のもの(
~/Library/ApplicationSupport/Code/User/settings.jsonなど)
- macOSに固有のもの(
# vim
.vim ${HOME}/.vim
# neovim
nvim ${HOME}/.config/nvim
# zsh
.zsh.d ${HOME}/.zsh.d
.zshenv ${HOME}/.zshenv
# Visual Studio Code
Code/User/settings.json ${HOME}/.config/Code/User/settings.json
Code/User/keybindings.json ${HOME}/.config/Code/User/keybindings.json
Code/User/locale.json ${HOME}/.config/Code/User/locale.json
Code/User/snippets ${HOME}/.config/Code/User/snippets
# Visual Studio Code
Code/User/settings.json ${HOME}/Library/ApplicationSupport/Code/User/settings.json
Code/User/keybindings.json ${HOME}/Library/ApplicationSupport/Code/User/keybindings.json
Code/User/locale.json ${HOME}/Library/ApplicationSupport/Code/User/locale.json
Code/User/snippets ${HOME}/Library/ApplicationSupport/Code/User/snippets
link.sh を修正
これに対応して link.sh も修正します。
# !/bin/sh
# ~~~ 省略 ~~~
cd ${dotfiles_root}/dotfiles
for linklist in "linklist.Unix.txt" "linklist.$(uname).txt"; do
[ ! -r "${linklist}" ] && continue
__remove_linklist_comment "$linklist" | while read target link; do
# ~ や環境変数を展開
target=$(eval echo "${PWD}/${target}")
link=$(eval echo "${link}")
# シンボリックリンクを作成
mkdir -p $(dirname ${link})
ln -fsn ${target} ${link}
done
done
Tips
- gitのコミットメッセージの先頭にソフトウェア名を入れると見やすくなり、revert時などに便利です。
- 例: [vim] 行番号を表示するように変更 、 [bash] 履歴を10,000件保存するように変更
-
link.sh同様にunlink.shもあると意外と便利です。 - シェルの設定は機能ごとにファイルを分割すると管理しやすいです。
- 環境固有の設定ファイルを
example.local.shとし、.gitignoreに*.local.shを追加すると自動的に管理対象外となります。
- 環境固有の設定ファイルを
- 本当にどこでも動くようにするにはシェルスクリプトをPOSIXコマンド・オプションのみで書くと良いかもしれません
- 今回の例では
lnコマンドの-nオプションはPOSIXの範囲外です。
- 今回の例では
最後に
dotfiles の作り方をいくつかのステップに分けたため、予想以上に長くなってしまいました。
私のサンプルが https://github.com/Gandats/dotfiles-sample にあるので、よかったら参考にしてみてください。