Effectively Using .bash_profile

For many years I was a bit hazy on the difference between .bashrc and .bash_profile (or .profile). I knew that .bashrc was sourced by Bash when it ran an interactive shell, and I knew that .bash_profile was sourced by Bash when it ran a login shell, but I confess I didn't understand exactly how to use this distinction effectively.

When .bash_profile And .bashrc Are Run

Assuming you have your shell set to /bin/bash, there are generally three times when Bash will source your .bash_profile file:

A key thing to understand here is that when the .bash_profile file is sourced in this way, it will affect all future processes created from that SSH/X11/console session. Therefore it should only contain the most important configuration.

The .bashrc file will be run whenever a new terminal window is opened. It will not automatically be sourced if you log in via SSH or a virtual console. In a GNOME session (or whatever window manager you prefer) the .bashrc file will be executed every time you open a new terminal "window".

Combining The Two

Your .bash_profile file should set up everything that needs to be run just once and will be needed by any later programs. There are at least two important cases:

If you're using GNOME it will actually automatically launch a gnome-keyring-daemon process for you that acts as an SSH agent. I strongly recommend against using it. I wrote an article about this previously. In the previous article I advocated using Envoy, but now I prefer to just use a regular ssh-agent process which is simpler and more effective now that I figured out how to nuke all of the gnome-keyring stuff.

In my .bash_profile I have the following code:

eval $(ssh-agent) &>/dev/null
ssh-add &>/dev/null
export SSH_AUTH_SOCK

# source .bashrc only if this is a VT or SSH connection
if [ $(env | grep -c SSH_CONNECTION) -ne 0 ] || [ $TERM = "linux" ]; then
    source ~/.bashrc
fi

This creates an ssh-agent process in the usual way and adds my key to it. It also checks if I'm connected from an SSH connection, or if I'm logged in via a virtual console (uncommon, but happens from time to time). In either of those cases it will source .bashrc.

In my .bashrc file I have code related to setting up a decent prompt (i.e PS1 and PS2) and some useful interactive aliases and whatnot. The whole thing is pretty small. As I write this, my .bash_profile is 33 lines long and my .bashrc is 116 lines long (most of which is weird stuff I need for obsure reasons at work). Aliases and prompt configuration should only be defined in .bashrc, not in .bash_profile.

I strongly recommend against unconditionally sourcing .bashrc from your .bash_profile or .profile. You should only source it if you're actually in an interactive session, and the above is a good way to test that.

Update: It's been pointed out to me that instead of the byzantine check that I had above for checking for SSH_CONNECTION and TERM, one can simply do:

test -t 0 && source ~/.bashrc

This is kind of a nice approach because besides being simpler, it will work in a wider variety of environments (e.g. OS X).

Nuking gnome-keyring-daemon

It's really easy to prevent the gnome-keyring-daemon from running:

sudo ln -sf /dev/null /etc/xdg/autostart/gnome-keyring-ssh.desktop

Do this once and you'll never have to worry about it interfering with your ssh-agent process ever again.

In addition to this, in my .bashrc I have:

unset SSH_ASKPASS

In the unlikely situation where you don't have any SSH keys loaded this will prevent the annoying GNOME graphical popup from asking you for an SSH password.