Using rbenv with fish

By: Jeremy W. Sherman. 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
  if [ "$#" -gt 0 ]; then

  case "$command" in
    eval `rbenv "sh-$command" "$@"`;;
    command rbenv "$command" "$@";;

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]

    switch "$command"
        case rehash shell
            eval (rbenv "sh-$command" $argv)
        case '*'
            command rbenv "$command" $argv

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!