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:
- if you log into a machine over SSH
- if you log in via a Linux virtual console
- it will be sourced by GDM/GNOME if you have a graphical login session started in the usual way
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:
- you should set up your SSH agent here
- anything important in your
PATH
should be set up here, so that theexec()
family of system calls will be able to find executables
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.