Solist Work Blog

ソフトウェアエンジニア / IT navigator

.zsh_historyとMELPAの管理方法

ソフトウェアエンジニアにとって .zsh_history や .bash_history は財産です。私はzshがメインシェルなので以下 .zsh_history で統一して書いていきますが、bashでも基本的には同じ内容です。 履歴は多いほど役に立つのでシェルの履歴は10万を越えても消すべきではないでしょう。わたしはll ls la cd man scp vim nvim less ping open file which whois drill uname md5sum tracerouteなどの履歴を残さないように設定してあまり価値のない履歴が残らないように努力しています。

.zshrc

zshaddhistory() {
    local line=${1%%$'\n'}
    local cmd=${line%% *}

    # Only those that satisfy all of the following conditions are added to the history
    [[ ${#line} -ge 5
       && ${cmd} != ll
       && ${cmd} != ls
       && ${cmd} != la
       && ${cmd} != cd
       && ${cmd} != man
       && ${cmd} != scp
       && ${cmd} != vim
       && ${cmd} != nvim
       && ${cmd} != less
       && ${cmd} != ping
       && ${cmd} != open
       && ${cmd} != file
       && ${cmd} != which
       && ${cmd} != whois
       && ${cmd} != drill
       && ${cmd} != uname
       && ${cmd} != md5sum
       && ${cmd} != pacman
	   && ${cmd} != xdg-open
       && ${cmd} != traceroute
       && ${cmd} != speedtest-cli
    ]]
}

このコマンドから始まる場合は履歴に残らないようにしています。 これで無闇に履歴が増えなくなってよいです。

保持している履歴が多くなるにつれてその価値がますます高まっていきますし、ソフトウェアエンジニアを続ける限り使い続けるものですから、もし消えてしまったらほとんどの仕事で支障をきたすことでしょう。履歴を増やすためには長い年月をかけてまた育てなければいけないので非常につらい状態に追い込まれることになります。 コマンドを全て丸暗記しているソフトウェアエンジニアはおそらく存在しないので、ほとんどのソフトウェアエンジニアは.zsh_historyをCtrl-rで呼び出すことで対処しています。 以下のように設定するとCtrl-rを押すとfzfで .zsh_history が検索できるようになります。

.zshrc

function select-history() {
  BUFFER=$(history -n -r 1 | fzf-tmux -d --reverse --no-sort +m --query "$LBUFFER" --prompt="History > ")
  CURSOR=$#BUFFER
}
zle -N select-history
bindkey '^r' select-history

fzfで.zsh_historyを検索

.zsh_history は火事があっても守らなければいけない資産であることに疑いの余地はないでしょう。 商人の家が火事になったとき持って逃げるものの筆頭は顧客リストであると聞きました。 ソフトウェアエンジニアが火事の時もって逃げるべきものは自分のパソコンであることに異論はないでしょう。しかし、災害は火事だけではありません。津波がこようがミサイルが飛んでこようが火山が噴火しようが泥棒にパソコンをもっていかれようが .zsh_history は失いたくないものです。わたしは子供時代に川が氾濫しそうになって一番大事なものを持って逃げなさいと言われたときに持って逃げたものはレゴブロックでしたが、持って逃げることのできるものは重さや状況によって制限されてしまいます。FBIが対象者を尾行するときに一番効果的なのは尾行しないことであると何かの本で読みました。対象者の行動を分析して先回りするのが成功率が最も高い尾行方法なのだそうです。尾行しなくてよい状況を作ることが最善であるならば、ソフトウェアエンジニアは災害の時に何も持たずに逃げてよい状況をつくることが最善なのではないでしょうか。1 .zsh_historyは機密情報を含むこともありますので、GitHubで公開すべきものではないでしょう。ではどのようにして.zsh_historyを災害から守っていくのか考えたいと思います。

.zsh_historyを守る仕組み

ディレクトリを作っておきます。

mkdir -p ~/Dropbox/zsh/backup/

まず、Dropboxのzshディレクトリのbackupフォルダにローテートした履歴を作っておきます。 次のコマンドで履歴を世代管理したい回数だけ実行します。8世代管理したいなら8回実行します。

ノーマルバージョン

tar cfz ${HOME}/Dropbox/zsh/backup/`date '+%Y%m%d%H%M%S'`.tar.gz -C ${HOME}/ .zsh_history

暗号化バージョン

gpg -c ${HOME}/.zsh_history; mv ${HOME}/.zsh_history.gpg ${HOME}/Dropbox/zsh/backup/`date '+%Y%m%d%H%M%S'`.gpg

暗号化バージョンは機密情報を二段階認証しているとはいえDropboxにアップロードすることはまかりならんという頭の硬い組織に属している人向けです。私はノーマルバージョンを使っています。暗号化の安全性についてはこちらの記事で確認してください。暗号化バージョンはパスワードを聞かれるので12文字以上のパスワードを入力してください。毎朝打てるパスワードで強度が強そうなものを選びましょう。

私は8世代の .zsh_history を管理しているので8日分の履歴があります。 この状態で以下のコマンドを毎朝実行すると次のような動きをするようになっています。

ノーマルバージョン

rm -rf ${HOME}/Dropbox/zsh/backup/`ls -rt ${HOME}/Dropbox/zsh/backup | head -n 1`; tar cfz ${HOME}/Dropbox/zsh/backup/`date '+%Y%m%d%H%M%S'`.tar.gz -C ${HOME}/ .zsh_history

暗号化バージョン

rm -rf ${HOME}/Dropbox/zsh/backup/`ls ${HOME}/Dropbox/zsh/backup | grep gpg | head -n 1`; gpg -c ${HOME}/.zsh_history; mv ${HOME}/.zsh_history.gpg ${HOME}/Dropbox/zsh/backup/`date '+%Y%m%d%H%M%S'`.gpg

8世代管理している履歴のうちから一番古いものを削除して、現在の .zsh_history をバックアップフォルダにバックアップします。ローテートしながらbackupしているということです。なぜローテートしながらバックアップしているのかというと、バックアップが一つしかないとファイルが破損した場合復元できなくなるからです。ファイルが破損した時にどれか一つでもファイルを救い出せれば、被害は最大でも一週間分の履歴を失うだけですみます。これくらいなら許容範囲でしょう。 Dropboxはおそらく3つくらいのコピーが複数のサーバーに離れて管理されているでしょうが、DropboxのソフトウェアエンジニアがヘマをしたときのためにDropboxGoogle Driveを同期しましょう。この目的のためrcloneを使用します。

sudo pacman -S rclone
rclone config

Google Driveを選んでセットアップしましょう。Google Driveの接続名をgoogledriveに設定します。クライアントID、認証キーの入力は省略できます。auto configはNを選択します。ブラウザで認証したらコマンドラインに認証コードをペーストすれば準備完了です。Google Driveにbackupフォルダを作って何かファイルが存在する状態で確認しましょう。

rclone ls googledrive:backup

これで以下のようにGoogle Driveのbackupフォルダにあるファイルが見えるはずです。

rcloneでGoogleDriveに接続する

動作確認ができたらDropboxのzshディレクトリとGoogle Driveのbackupフォルダを同期しましょう。

rclone sync ${HOME}/Dropbox/zsh googledrive:backup

これでDropboxのzshディレクトリがGoogle Driveのbackupディレクトリに同期されますので、Dropboxのソフトウェアエンジニアがヘマをしても安心です。DropboxとGoogleのソフトウェアエンジニアが同時にヘマをして、かつ私のパソコンが泥棒に盗まれるという事態が同時に起こる確率はものすごく低いと思うので考慮しなくてもよいと思います。

以上のコマンドを毎朝たたくのは面倒なのでコマンド一つにしましょう。

zshbackup

コマンド一つでこれらの処理がすべて完了するようにします。これくらいなら毎朝実行するのはつらくありません。コーヒーを入れている間などに毎日実行するようにしましょう。

.zshrcノーマルバージョン

alias zshbackup='rm -rf ${HOME}/Dropbox/zsh/backup/`ls -rt ${HOME}/Dropbox/zsh/backup | head -n 1`; tar cfz ${HOME}/Dropbox/zsh/backup/`date '+%Y%m%d%H%M%S'`.tar.gz -C ${HOME}/ .zsh_history; rclone sync ${HOME}/Dropbox/zsh googledrive:backup'

.zshrc暗号化バージョン

alias zshbackup='rm -rf ${HOME}/Dropbox/zsh/backup/`ls ${HOME}/Dropbox/zsh/backup | grep gpg | head -n 1`; gpg -c ${HOME}/.zsh_history; mv ${HOME}/.zsh_history.gpg ${HOME}/Dropbox/zsh/backup/`date '+%Y%m%d%H%M%S'`.gpg; rclone sync ${HOME}/Dropbox/zsh googledrive:backup'

.zshrcのaliasで実現しています。これで .zsh_history を失うリスクを今後も心配しなくてもよさそうです。

複数のパソコンを使う場合

自宅と会社で異なるパソコンを使っている場合は.zshrcに以下のように設定してはじめからDropboxに.zsh_historyを置いておけばよいでしょう。

.zshrc

HISTFILE=~/Dropbox/zsh/.zsh_history

会社と家を瞬間移動できる人間でない限り、Dropboxの同期の速度を越えて帰宅することはできないと思うので.zsh_historyがコンフリクトすることはないでしょう。この場合、.zsh_historyの位置が変わるのでzshbackupコマンドは適宜変更してください。私ははじめからDropboxに.zsh_historyを置いておいてzshbackupで一日一回バックアップしているので私のdotfilesが参考になると思います。

ただし頭の硬い組織に属している人はこの方法は使えません。Dropboxに生の.zsh_historyを置かなければならないので暗号化できないからです。頭の硬い組織に属している人で会社と家で異なるパソコンを使う場合はパソコンから離れる時は必ずzshbackupを実行するようにすれば.zsh_historyがコンフリクトしないでしょう。ただしパソコンを立ち上げた時は必ず暗号化したバックアップから最新の.zsh_historyを取り出して同期する必要があります。zshbackupを実行してからシャットダウンするシャットダウンラッパーコマンドと暗号化したデータから最新の.zsh_historyを取り出すコマンドを作成するなどして対処すればよいのではないでしょうか。

MELPA

同じ方法でMELPAのパッケージも管理しています。 MELPAのパッケージは誰でもMaintainerになれるわけではないので質が高く仕事にならないようなバグが長期間放置されることはほとんどありませんが、万が一Emacsが動かないようなバグで仕事に支障をきたす事態が起きないとは限らないので私が使っているMELPAパッケージはローテートで8世代分のバックアップをとっています。このような事態になったらバックアップのMELPAパッケージを適応したEmacsで起動すれば仕事に支障をきたすことはないでしょう。MELPAの品質は高いので心配はないでしょうが、このように準備をしておくと気兼ねなくMELPAのパッケージを最新に追従しておくことができます。

mkdir -p ${HOME}/Dropbox/emacs/elpa/

ディレクトリを用意しておきます。

tar cfz ${HOME}/Dropbox/emacs/elpa/`date '+%Y%m%d%H%M%S'`.tar.gz -C ${HOME}/.emacs.d elpa

まずは8世代分のMELPAパッケージを管理したいので8回このコマンドをたたきます。 パッケージ管理にCaskを使っている場合はelpaディレクトリに保存されないので適宜変更してください。

.zshrc

alias melpabackup='rm -rf ${HOME}/Dropbox/emacs/elpa/`ls -rt ${HOME}/Dropbox/emacs/elpa | head -n 1`; tar cfz ${HOME}/Dropbox/emacs/elpa/`date '+%Y%m%d%H%M%S'`.tar.gz -C ${HOME}/.emacs.d elpa'

これで毎朝

melpabackup

と叩くだけでMELPAで使っているパッケージがローテートしてバックアップされます。 私は毎朝MELPAパッケージをUpdateするのでその直前にこのコマンドを実行するようにしています。

Makefile

最後にrcloneが気に入ったのでMakefileを作っておきましょう。 rclone.confは機密情報を含んでいますので設定ファイルはDropboxで管理します。

rclone: ## Install and deploy rclone
	sudo pacman -S rclone
	chmod 600   ${HOME}/Dropbox/zsh/rclone.conf
	mkdir -p ${HOME}/.config/rclone
	ln -vsf ${HOME}/Dropbox/zsh/rclone.conf   ${HOME}/.config/rclone/rclone.conf

allinstall: ttf-cica install init initdropbox pipinstall goinstall aur mozc neomutt docker mariadb redis rbenv rustinstall nodeinstall screenkey dnsmasq desktop chromium jekyll sxiv zeal zoom toggle sylpheed rclone

これで次回のクリーンインストール時には

make rclone

だけでこの設定が適応されます。

make allinstall

を実行するとmake rcloneも実行されるので更に簡単になります。


  1. 災害時に何ももたずに逃げるためには開発環境であるパソコンがなくなってもよい状況を作らなければなりません。私の場合はThinkPadを買ってくればいつでも開発環境が再現できるようにしています。詳しくはこちらの記事を参考にしてください。

タグ一覧

お仕事の依頼はこちらからどうぞ

お仕事の依頼はこちらからどうぞ