2016-03-01:
Using Ruby rbenv with tcsh / csh - A Complete Solution

tcsh? | The Problem | The Solution | Installation | Updates | Bugs/Errata


tcsh? Really?

Like many people, I use tcsh for my interactive shell.

And I know many of you are prepared to go into a rant now about how tcsh is a terrible scripting language. I actually agree. But it's also a fantastic interactive shell. I have no need for my interactive shell to be a scripting language as well. In fact, I'm unclear why anyone would use sh/bash as a scripting language. Yes, bash is better than than tcsh for scripting, but it's inferior to perl/ruby/python/etc..

And regardless of your religious beliefs regarding tcsh, there are many people who are required to use tcsh. So bash lovers can hit the "Back" button now, this page is not for you.

The Problem

rbenv is a great system for managing multiple ruby versions and multiple gemsets.

Unfortunately, rbenv requires bash heavily, it uses a combinations of "shims" (effectively wrappers to the ruby executables) as well as some bash functions and evals.

We can partially make use of rbenv by only using the shims, by simply setting the $PATH variable accordingly, as shown by HPLOGSDON.

Unfortunately this breaks:

But that info inspired me to come up with a complete solution.

The Solution

I solved all of this with a wrapper which is eval'd for all rbenv calls, this is done with an alias that is set when they call the init. So now all you need to do is put the wrapper in your path as 'rbenvWrap' and then add this to your .tcshrc:
eval `rbenvWrap init -`
Source your .tcshrc (or logout and login again) and you're done (assuming you've also installed rbenv). You don't need to worry about the wrapper anymore, all of your rbenv commands will work just like they do on bash. Example:
tcsh% echo $RBENV_VERSION 
RBENV_VERSION: Undefined variable

tcsh% rbenv versions
* system (set by /home/dave/.rbenv/version)
  2.1.2

tcsh% ruby -v
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]

tcsh% rbenv shell 2.1.2

tcsh% rbenv versions
  system
* 2.1.2 (set by RBENV_VERSION environment variable)

tcsh% echo $RBENV_VERSION 
2.1.2
Command completion also works, so for example if you hit tab:
tcsh% rbenv sh<tab>
shell shims

tcsh% rbenv shell <tab>
2.1.2    system    --unset

tcsh% rbenv shell -<tab>
tcsh% rbenv shell --unset
Magic!

The completion setup happens in the .tcshrc eval and may slow down some older machines (it takes less than half a second on my 2.5GHz quad core). It also only works with tcsh, it will give "complete: command not found" errors with csh. It should detect csh as your shell, but if you want to be sure to avoid using the completions, then you can just change the eval line in your .cshrc to: (add 'csh' to the end)

eval `rbenvWrap init - csh`
You can see how long it takes in both cases by timing the commands:
% time rbenvWrap init - > /dev/null
% time rbenvWrap init - csh > /dev/null
For serious power-users you could also take the full complete command that 'rbenvWrap init -' generates and put it in your .tcshrc and then not generate it each time, but this also means that future changes to rbenv completion will not get updated on your system.

Installation

To install:
  1. Download the 'rbenvWrap' script (it's ruby, of course) and install it in your path.
  2. Install rbenv. There are simple instructions at the top of the script as well as available directly from the rbenv maintainers - just ignore their bash suggestions unless you wish to use bash as well - they will both work).
  3. Add the eval `rbenvWrap init -` to your .tcshrc
I've also included an optional 'gem' wrapper because, much to my surprise, doing system (root) installs of gems will break unless your umask is set properly, this is the wrapper I use to make sure the umask is set to 22. It needs to be extra clever with rbenv so that it doesn't interfere with the rbenv 'gem' wrapper. These scripts are licensed under the Creative Commons Attribution 4.0 International for freedom of usability.

Updates

Updated May 2020: The 'rbenv shell' command was now outputting things like:
RBENV_VERSION_OLD="$RBENV_VERSION"
setenv RBENV_VERSION "2.6.0"
So I updated it to handle multiline commands, as well as the fact that we might have a 'var=$othervar' where $othervar was not defined, something tcsh does not handle very well.

Bugs/Errata

None that I know of.

If you find any, please feel free to contact me

rbenvWrap is prone to failure on future rbenv versions if the output of the rbenv eval'd commands changes to something it can't translate. If that happens let me know and I'll update rbenvWrap (if possible). Otherwise, this system should still work with general updates to the rbenv system.


Back to Solutions.

DaveSource.com - Dave's geek site GetDave.com - all the current Dave Pointers. MarginalHacks - I have an elegant script for that, but it's too small to fit in the margin.