Mac OS X, tmux, zsh, and rbenv

Disclaimer: This post is likely relevant for very few users; but I am certain that the Internet is big enough for me to not be alone with this winning combo.

I recently migrated from GNU Screen to tmux. As Ruby is a big part of my work, and it’s nice to be able to use different versions for different projects, rbenv fits my needs well. (Yes, RVM may be more popular, but I prefer the approach that rbenv takes.)

rbenv injects its bin path into your environment’s PATH, which allows your selected version of ruby to run when you call it instead of system-provided /usr/bin/ruby.

Mac OS X uses a clever utility called path_helper to work some magic on your $PATH.

But back to tmux and screen. For some things to work properly (eg. launchctl, pbcopy, pbpaste), the user space must be attached to the running GUI login session. I won’t pretend to know how tmux and screen do their things, and so if you’re interested in reading more, Chris Johnsen () provides an explanation (and solution!).

I have zsh set to be my default shell on Mac OS X. When I start a new Terminal session, zsh loads in the config, first from /etc/zshenv, and then from the .zsh* files in my home. The /etc/zshenv that ships with Mac OS X is as follows:

# system-wide environment settings for zsh(1)
if [ -x /usr/libexec/path_helper ]; then
  eval `/usr/libexec/path_helper -s`
fi

This sets up the PATH (and MANPATH). Dot files in my home then update my PATH to fit my needs. Specifically, rbenv shifts the necessary paths onto the front. But, for some reason, when a new window is opened in tmux, /etc/zshenv seems to run either at the wrong time or in the wrong way, and path_helper is not smart enough to know that the PATH has already been processed by the parent shell that started tmux. It then shoves all of its stuff at the start of the PATH (again), overriding rbenv. The solution is simple, though ugly because it requires patching a system file which could (and will) be overwritten by some future update from Apple.

Adding a quick check for $TMUX makes everything work wonderfully (and how it should). Perhaps I’ll file a radar with Apple on this. But until then, here’s my patched /etc/zshenv:

# system-wide environment settings for zsh(1)
if [ -x /usr/libexec/path_helper ]; then
  if [ -z "$TMUX" ]; then
    eval `/usr/libexec/path_helper -s`
  fi
fi