Dotfiles II: Choosing BASH Startup Files
A post or two back, I looked at having BASH detect if I was on my “desktop” (for lack of a better word) or a server and decided the best approach was to hard-code that fact. I casually tossed the configuration in my .bashrc. Was that the right place? BASH can potentially load any number of files at start up, and it’s not inherently obvious which are used when. There are three cases:
- An interactive login shell
- An interactive non-login shell
- A non-interactive shell.
What on earth is the difference between a login and a non-login shell? This is an ancient UNIX concept. A login shell is one where the user is showed as logged in (added to utmp and wtmp). By default the user is also shown system information: their last login time, perhaps a Message of the Day, load averages, maybe notices of pending upgrade.
Non-login shells just start, no messages, and they do not get logged
(though activity may be, if accounting is turned on), not appearing in
the output of last
or w
.
The distinction was much more important when people used real terminals and things like terminal type and device options need to be set.
How a shell is invoked determines if it’s a login or non-login shell. Console and ssh logins are login shells. On the Mac new windows and tabs in both Terminal and iTerm default to login shells. tmux, screen, xterm, and sudo all create non-login shells by default. All of these can be configured to star either kind of shell.
An interactive BASH login shell looks for ~/.bash_profile
,
~/.bash_login
, then ~/.profile
running the first one it
finds. There’s no difference between ~/.bash_profile
and
~/.bash_login
, but ~/.profile
is also used by the Bourne Shell. I
find it’s best to avoid using ~/.profile
as BASH is not backward
compatible with it.
A non-login interactive shell runs only ~/.bashrc
.
There’s almost no difference between login and non-login shells. I can’t think of anything in terms of functions, aliases, or environmental variable I wouldn’t want in both. If there’s any difference it would be that I might want to display something on login.
Given that, my setup is pretty simple. I put everything of importance
in ~/.bashrc
. I then create a ~/.bash_login
that contains:
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
That way my login shells always load ~/.bashrc
. If there are any
things I want to run only at login, I can add them to the
bash_login
. I chose ~/.bash_login
because that make it clear to me
what it’s for.
However, this is not quite the Linux way. Most distros use the same
general approach, but use ~/.profile
as the login file. Because
~/.profile
is also using by /bin/sh (typically
dash), ~/.profile
gets
some logic to decide if it’s BASH or the vanilla Bourne shell.
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
Things are also different on the Mac. Like LINUX, it’s default shell is BASH. However, when you create a new user on Mac OS, it does not get any BASH start up files. It’s a blank slate, which is always a nice place to start.
I prefer my approach to the Linux one for a couple of reasons, it
doesn’t require special handling as ~/.bash_login
is only
run by BASH, if I really need Bourne shell configuration, I can keep
it separate in my ~/.profile
, and, as noted, I can tell by the name
when ~/.bash_login
is run. And when was the last time I used the
Bourne shell anyway?
However, if the Linux approach appeals to you, use it, it’s functionally the same.
As a side note, I rarely use TCSH anymore, but it actually follows
this pattern by default, login shells read ~/.login
and all shells
read ~/.tcshrc
(or ~/.cshrc
if it exists and ~/.tcshrc
doesn’t).
And a final word of caution. Some programs will modify your dotfiles to add them selves to your path, or load functions (RVM for example) in to the shell. Sometimes they are smart at look at which files you are using. Other times, they just pick one, possibly creating something you didn’t have and breaking your set up. Something to keep a eye on.
And thus the question is answered, my local settings are in the right place!
Comments