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!