Traditionally, when you log into a Unix system, the system would start one program for you. That program is a shell, i.e., a program designed to start other programs. It's a command line shell: you start another program by typing its name. The default shell, a Bourne shell, reads commands from ~/.profile
when it is invoked as the login shell.
Bash is a Bourne-like shell. It reads commands from ~/.bash_profile
when it is invoked as the login shell, and if that file doesn't exist¹, it tries reading ~/.profile
instead.
You can invoke a shell directly at any time, for example by launching a terminal emulator inside a GUI environment. If the shell is not a login shell, it doesn't read ~/.profile
. When you start bash as an interactive shell (i.e., not to run a script), it reads ~/.bashrc
(except when invoked as a login shell, then it only reads ~/.bash_profile
or ~/.profile
.
Therefore:
~/.profile
is the place to put stuff that applies to your whole session, such as programs that you want to start when you log in (but not graphical programs, they go into a different file), and environment variable definitions.
~/.bashrc
is the place to put stuff that applies only to bash itself, such as alias and function definitions, shell options, and prompt settings. (You could also put key bindings there, but for bash they normally go into ~/.inputrc
.)
~/.bash_profile
can be used instead of ~/.profile
, but it is read by bash only, not by any other shell. (This is mostly a concern if you want your initialization files to work on multiple machines and your login shell isn't bash on all of them.) This is a logical place to include ~/.bashrc
if the shell is interactive. I recommend the following contents in ~/.bash_profile
:
if [ -r ~/.profile ]; then . ~/.profile; fi
case "$-" in *i*) if [ -r ~/.bashrc ]; then . ~/.bashrc; fi;; esac
On modern unices, there's an added complication related to ~/.profile
. If you log in in a graphical environment (that is, if the program where you type your password is running in graphics mode), you don't automatically get a login shell that reads ~/.profile
. Depending on the graphical login program, on the window manager or desktop environment you run afterwards, and on how your distribution configured these programs, your ~/.profile
may or may not be read. If it's not, there's usually another place where you can define environment variables and programs to launch when you log in, but there is unfortunately no standard location.
Note that you may see here and there recommendations to either put environment variable definitions in ~/.bashrc
or always launch login shells in terminals. Both are bad ideas. The most common problem with either of these ideas is that your environment variables will only be set in programs launched via the terminal, not in programs started directly with an icon or menu or keyboard shortcut.
¹ For completeness, by request: if .bash_profile
doesn't exist, bash also tries .bash_login
before falling back to .profile
. Feel free to forget it exists.
The most common problem caused by misuse of shell startup files is that if you define environment variables in .bashrc
as opposed to .profile
, they are not defined in applications that are not launched from a shell in a terminal but rather from a GUI menu.
Defining environment variables from .bashrc
is generally not a good idea, but that's primarily because it's generally useless as the variables should already have been set at login time. It can cause a problem in practice if you (or an application) have deliberately changed the value of a variable (e.g. PATH
) in a program and you launch a shell from that program and expect the setting to have remained the same.
You can avoid the problem of environment variables being reset by defining a “sentinel” value, and not defining anything if the sentinel value is set:
if [ -z "$JMLANE_PROFILE_READ" ]; then
export ...
export JMLANE_PROFILE_READ=1
fi
Another problem caused by terminals starting login shells is that there are things that should only be done once when you log in, for example starting a password agent (e.g. ssh-agent
), or initiating a session (e.g. running startx
in certain circumstances). The sentinel variable avoids these issues.
A shell inside a terminal is always interactive. As long as you source .bashrc
from .bash_profile
when the shell is interactive, you don't need to worry about the terminal starting a login shell.
An additional wart of bash's startup file handling is that .bashrc
is read by non-interactive shells invoked by rshd or sshd. For example, when you do rsync somefile host.example.com:
, if your login shell on host.example.com
is bash, you can use .bashrc
there to set the path to include rsync
. You can tell you're in this situation because .bashrc
is read from a non-interactive shell.
## .bashrc
if [[ $- != *i* ]]; then
# either .bashrc was executed explicitly or this is a noninteractive rsh/ssh session
fi
Best Answer
The most possible reason is that your default
bashrc
file is~/.profile
. On myMavericks
with defaultbash
v3.
, it happens to be like that.