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、よくできたツールだなぁとしみじみ思った。