rbenv rehashをちゃんと理解する
rbenv の rehash というコマンドについてちゃんと理解するべく調べたのでまとめる。なお調べたのはバージョン1.1.2の rbenv。
$ rbenv --version
rbenv 1.1.2
もしかすると間違っている部分があるかもしれないので、気づいた方はコメントなどいただけるとありがたい。
rbenv rehash とは何か
rbenv rehash コマンドを実行すると、大まかには ~/.rbenv/versions/*/bin/ 以下のファイルを ~/.rbenv/shims/ 以下にコピーする。
なぜコピーする必要があるかというと、通常 PATH が通っているのは ~/.rbenv/shims 以下となっているからで、ここにコピーしないと rspec とか rubocop といった Gem が提供するコマンドを実行できないからである。
rbenv init がやっていること
ここで、「rbenv は使っているけど ~/.rbenv/shims に PATH を通した記憶なんて無いぞ」という人もいるかもしれないが、zshrc や bashrc といったシェル起動時に読み込まれるファイルに eval "$(rbenv init -)" と書いた記憶は無いだろうか?
README にちゃんと書かれているのだが、rbenv init - を実行することで、以下のことがなされている。
- (1)
~/.rbenv/shimsを環境変数 PATH の先頭に追加する - (2) コマンドの補完用のシェルスクリプトを読み込む
- (3) shim の rehash、すなわち
rbenv rehashの実行 - (4) sh dispatcher をインストールする
ここで大事なのは (1) のところで、環境変数 PATH へ shims のパスを追加するということを rbenv init - により行われているということだ。
いつ rbenv rehash を実行すればいいか
ここまでの話を踏まえると、実行コマンドを含む Gem (rspec, rubocop, etc..) をインストールした場合には、rbenv rehash コマンドを実行しないといけないことが想像できると思う。
なぜならば、gem install xxx と実行したときには ~/.rbenv/versions/*/bin/ の方にしかインストールされず、そこに配置された実行ファイルをパスの通っている ~/.rbenv/shims 以下にコピーしないと実行できないからだ。
…と自分は考えたのだが、この理解は少し間違っていることが後から判明した。
なぜか? 実は rbenv は gem install xxx をしたタイミングで hook スクリプトを噛ませていて、それが自動的に rbenv rehash を実行していたのである。よって自分で明示的に rbenv rehash を実行する必要はない。
rbenv の歴史はあんまり調べてないのでよく知らないのだけど、もともとは rbenv-gem-rehash という rbenv plugin があって、それがこの動きをしていたのだけれど、今は rbenv の core に移植されているということのようだ。
実際に試してみた
実際に、gem install をしたときに自動で rbenv rehash が実行されていることを確認したのでご紹介。 今回は、今の自分の環境にはインストールされていなかった colorls という gem を使って確認する。
まず、gem install 前の状態。colorls は存在しない。
$ ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin18]
$ ls ~/.rbenv/shims/ | grep colorls
# => 結果なし
colorls を install する。
$ gem install colorls
Fetching colorls-1.4.3.gem
..snip..
Successfully installed colorls-1.4.3
Parsing documentation for colorls-1.4.3
Installing ri documentation for colorls-1.4.3
Done installing documentation for colorls after 0 seconds
1 gem installed
shims 以下を見てみると、すでにいることが確認できる。
$ ls ~/.rbenv/shims/ | grep colorls
colorls
当然、コマンドの実行もできる。

rehash をいつ実行するか?の考察
このプラグインのおかげもあり、rbenv rehash コマンドを明示的に実行しないといけないケースはそんなに多くないんじゃないかと思う。
そもそも、ログインシェル起動時のタイミングで rbenv init - により自動で rehash は実行されているので、コマンド実行するよりも新規でセッションを立ち上げたほうが楽な気すらする(tmux とか使っていると特に)。
新しいバージョンの ruby をインストールしたときくらいかな?と今は考えている。
まとめ
- rbenv rehash によって、
rspecやrubocopといったコマンドが実行できるようになる - rbenv rehash は
rbenv initのタイミングやgem installのタイミングで裏で動いているので、明示的に実行しないといけないケースは少なそう
rbenv、よくできたツールだなぁとしみじみ思った。