rvm or the Ruby Version Manager, works perfectly fine when there is a single version of Ruby to be run on the system (among multiple versions installed, of course) around the entire system. In a production scenario, updating ruby itself is a task which is not taken lightly!
This worked perfectly until I encountered two quite different situations –
One scenario was where I wanted to execute a command via ssh
into the server. So something like –
ssh user1@server1 'ruby ~/program.rb'
The other being when I wanted to run a ruby program via cron
In both these cases, I kept getting the error rvm not found
. Initially, I couldn’t understand this at all, because every time I logged in and ran the program or the command it would run prefectly.
And then I learnt about the difference between a login and a non-login shell.
A login shell is created after a successful login of a user or via the switch user su - user1
command.
This executes the following in order –
- executes
/etc/profile
/etc/profile
executes all scripts in/etc/profile.d/
- executes the user’s
~/.bash_profile
~/.bash_profile
executes the user’s~/.bashrc
~/.bashrc
executes `/etc/bashrc`
A non-login shell, on the other hand, executes the following in order –
- executes the user’s
~/.bashrc
- executes
/etc/bashrc
/etc/bashrc
calls the scripts in/etc/profile.d
A key thing to note here is that the user’s .bashrc
gets executed in both the steps.
Now, one of the lines right at the top of the .bashrc
script is this –
# If not running interactively, don't do anything [ -z "$PS1" ] && return
Since a non-login shell is not running interactively, the return gets executed. Anything further down, doesn’t.
For rvm
, we need to source the following in our .bashrc
file –
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
If this line is added at the bottom of the .bashrc
, then the non-interactive shell never gets to source rvm
.
Because of this, it should always be added towards the top of the .bashrc
file before the check for the non-interactive shell.
I added an additional comment to indicate why it is there –
# IMPORTANT - load rvm for non-login shells e.g. Net:SSH [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # If not running interactively, don't do anything [ -z "$PS1" ] && return