ちゃんと理解するrbenv : (4) shimsを理解する
はじめに
本記事は、「ちゃんと理解する rbenv」の第4回です。
※ 前回の記事
今回は、rbenv における重要な概念である shims について整理します。
shims とは
shims は rake、rubocop、rspec などといった Ruby のコマンド単位で生成される実行可能なシェルスクリプトです。rbenv によって作られています。
shims は通常、~/.rbenv/shims 以下に配置されています。筆者の環境の ~/.rbenv/shims は次のようになっていました。
$ ls ~/.rbenv/shims
bundle htmldiff nokogiri rbs rubocop solargraph y2racc
bundler irb racc rdoc ruby thor yard
erb kramdown racc2y reverse_markdown ruby-parse tilt yardoc
gem ldiff rake ri ruby-rewrite typeprof yri
shims には全てのバージョンの Ruby の実行可能コマンドが配置されます。
例えば 2.7.3 で rubocop をインストールし、3.0.1 で rspec をインストールした場合、shims ディレクトリには rubocop と rspec の両方が配置されることになります。
shims の役割
rubocop を例にして説明します。
通常、rubocop コマンドを実行すると rubocop という gem が提供する実行可能ファイルが実行されます。
rbenv を使っているとその実行可能ファイルは ~/.rbenv/versions/X.X.X/bin/rubocop に配置されています (X.X.X の部分はバージョン)。
しかし、rbenv を使っている環境においては shims に配置された ~/.rbenv/shims/rubocop が最初に呼び出されます。
こうして実行された shim が何をしているかというと、
- 現在の Ruby のバージョンを特定する
- 特定したバージョンの Ruby の本来の実行可能ファイルである
rubocopコマンドを実行する
ということをしています。

上の図のように、複数のバージョンの Ruby がありその全てで rubocop をインストールしている場合でも、rbenv の shim を介すことで適切なバージョンの Ruby を選択し、その先の rubocop コマンドにディスパッチすることが可能になります。
環境変数 PATH と shims
これまで整理してきたように shims を機能させるには、Ruby のコマンドが呼びされたとき 必ず最初に shim が実行される ようにしないといけません。rbenv はこれをどのようにして実現しているでしょうか?
第2回 基本的な使い方 のときに rbenv の初期設定として、.zshrc ファイルに eval "$(rbenv init -)" という設定を追記したことを覚えているでしょうか。実はこの rbenv init を実行することで、環境変数 PATH の先頭に ~/.rbenv/shims を追加するということが裏で行われています。
以下は筆者の環境における PATH 環境変数の値です。PATH の先頭に shims へのパスがあることがわかります。
$ echo $PATH
/Users/h3pei/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:...(省略)
環境変数 PATH は、ruby に限らずシェル上で実行されたコマンドを探すときのパスの一覧が : 区切りで記述されています。このとき前にあるパスほど優先されます。
よって、一番先頭にある shims 以下に存在すれば必ず最初に実行させることができる、という仕組みになっているのです。
rbenv はいつ shims を作るのか
ところで、shims ディレクトリ以下のスクリプトはいつどのようにして作られるでしょうか?これも当然 rbenv がやっているわけですが、これは rbenv の rehash という処理が行われたタイミングで作られています。
そしてこの rehash 処理も rbenv init により呼び出されています。
rehash の詳細については rbenv rehash をちゃんと理解する という過去の記事に書いているので、興味のある方は参考にしてください。
まとめ
本記事では shims を中心にして関連する概念の整理をしました。
- shims は、Ruby のコマンド単位で生成される実行可能なシェルスクリプト。通常
~/.rbenv/shims以下に配置される。 - Ruby のコマンドを実行すると、最初に shims 以下のスクリプトが実行される。その後に Ruby バージョンを特定した上で、shim から本来のコマンドが呼び出される
rbenv initは shims のパスを環境変数 PATH の先頭に追加するということと、rbenv rehashにより shim を生成する仕事をしていた
余談ですが、shim という単語には「部品の間にはさんで水平にしたり高さや位置を調整する板」とか「詰め木」という意味があるようです。最初、筆者は shim という見慣れない単語を見て ? となりましたが、このように役割を理解するとピンと来る名前だなぁと感動しました。rbenv の shim もコマンド実行と本来の実行可能ファイルの間に入り込んで、交通整理をしていますよね。