Using rbenv with fish
By: . Published: . Categories: ruby fish-shell.I switched from zsh to fish shell a month or so ago.
I lost bang-history (no more !?gi) and gained a shell small enough to
understand and write scripts for without fearing I’m going to step into
some gotcha from the 1970s. No more shell-as-quirks-mode!
There’s a downside to shifting to a non-POSIX shell, though: scripts intended to modify the shell environment itself no longer Just Work.
This tripped me up in one case: rbenv, the Ruby environment and version
manager.
rbenv expects you to run the output of rbenv init in your shell.
This fixes up your PATH, rebuilds rbenv's sense of the world,
and lastly redefines rbenv as a dispatching function.
rbenv provides a few different flavors of script, but none is for fish.
No problem! Let’s rewrite this script for fish.
When you run rbenv init, it dumps out a call to eval:
# Load rbenv automatically by adding
# the following to your profile:
eval "$(rbenv init -)"
When you run that bit of code, you see something like:
export PATH="/Users/jeremy/.rbenv/shims:${PATH}"
rbenv rehash 2>/dev/null
rbenv() {
typeset command
command="$1"
if [ "$#" -gt 0 ]; then
shift
fi
case "$command" in
rehash|shell)
eval `rbenv "sh-$command" "$@"`;;
*)
command rbenv "$command" "$@";;
esac
}
Translating this to fish is a good introduction to scripting fish.
Pop open fish help in a browser tab,
and lean on functions to look at how the functions provided with the shell
are coded.
With a bit of that, I ended up with:
set PATH "$HOME/.rbenv/shims" $PATH
rbenv rehash ^/dev/null
function rbenv
set -l command $argv[1]
if test (count $argv) -gt 1
set argv $argv[2..-1]
end
switch "$command"
case rehash shell
eval (rbenv "sh-$command" $argv)
case '*'
command rbenv "$command" $argv
end
end
I bet there’s a fishier way to do this,
but it’s working fine for me.
If you’ve been considering adopting fish as your shell
but ran into rbenv as a blocker,
this should get you past that. Enjoy!