Why ~/.bash_profile is not getting sourced when opening a terminal?
Problem
I have an Ubuntu 11.04 Virtual Machine and I wanted to set up my Java development environment. I did as follows
sudo apt-get install openjdk-6-jdk
-
Added the following entries to ~/.bash_profile
export JAVA_HOME=/usr/lib/jvm/java-6-openjdk export PATH=$PATH:$JAVA_HOME/bin
Save the changes and exit
-
Open up a terminal again and typed the following
echo $JAVA_HOME (blank) echo $PATH (displayed, but not the JAVA_HOME value)
Nothing happened, like if the export of JAVA_HOME and it's addition to the PATH were never done.
Solution
I had to go to ~/.bashrc and add the following entry towards the end of file
#Source bash_profile to set JAVA_HOME and add it to the PATH because for some reason is not being picked up
. ~/.bash_profile
Questions
- Why did I have to do that? I thought bash_profile, bash_login or profile in absence of those two get executed first before bashrc.
- Was in this case my terminal a non-login shell?
- If so, why when doing su after the terminal and putting the password it did not execute profile where I had also set the exports mentioned above?
~/.bash_profile
is only sourced by bash when started in login mode. That is typically when you log in at the console (Ctrl+Alt+F1..F6), connect via ssh, or use sudo -i
or su -
to run commands as another user.
When you log in graphically, ~/.profile
will be specifically sourced by the script that launches gnome-session (or whichever desktop environment you're using). So ~/.bash_profile
is not sourced at all when you log in graphically.
When you open a terminal, the terminal starts bash in (non-login) interactive mode, which means it will source ~/.bashrc
.
The right place for you to put these environment variables is in ~/.profile
, and the effect should be apparent next time you log in.
Sourcing ~/.bash_profile
from ~/.bashrc
is the wrong solution. It's supposed to be the other way around; ~/.bash_profile
should source ~/.bashrc
.
See DotFiles for a more thorough explanation, including some history of why it is like it is.
(On a side note, when installing openjdk via apt, symlinks should be set up by the package, so that you don't really need to set JAVA_HOME
or change PATH
)
You can check if your Bash shell is started as a login-shell by running:
shopt login_shell
If the reply is off
you are not running a login shell.
Read the Bash manual's invocation section on how Bash reads (or does not read) different configuration files.
Excerpt from man bash
:
When bash is invoked as an interactive login shell, or as a non-interactive shell with the
--login
option, it first reads and executes commands from the file/etc/profile
, if that file exists. After reading that file, it looks for~/.bash_profile
,~/.bash_login
, and~/.profile
, in that order, and reads and executes commands from the first one that exists and is readable.
su
on the other hand also does not start a login shell by default, you have to tell it to do so by using the --login
option.
I think it is worth mentioning that you can change the default of gnome-terminal to use a login shell (ie. bash -l) by editing the profile preferences.
go to Edit -> Profile Preferences -> Title and Command tab check the "Run command as a login shell" option
If you open a terminal or run su
the shell is not executed as a login shell but as a normal interactive shell. So it reads ~/.bashrc
but not ~/.bash_profile
. You can run su
with the -l
option to make it run your shell as a login shell.
When you are working with a GUI the shell is usually never run as a login shell so it's usually fine to put all yout stuff in ~/.bashrc
.
TL;DR
In classical recommended ubuntu setup, ~/.bash_profile
gets evaluated only in specific occasions. And it makes sense.
Put your stuff in ~/.bashrc
, it'll get evaluated everytime.
Ok, I want to understand, why does this make sense ?
Keypoints to understand what is going on:
- all processes on linux have and uses environment variables
- environment variables are inherited
- thus setting them once on the father of all your process is enough (especially if it requires some computation time.)
- the father of all your process is typically launched after you log in on your device (give your credentials).
- there are things you might want to do only once when you log in on your computer (check for new mail for instance...).
So "login" time is typically:
- In console mode, when you login (with Ctrl-Alt F1) or through
ssh
, as the shell will be the father of all process, it'll load your~/.bash_profile
. - In graphic mode, when you open your session, the first process
(
gnome-session
for classical ubuntu) will be in charge to read.profile
.
Ok, so where to put my stuff ?
It's rather complex, the full story is here. But here is a run down that is pretty common for ubuntu users. So considering that:
- you use
bash
shell, - you have a
~/.bash_profile
and follow the recommendation to add the loading of~/.bashrc
in your~/.bash_profile
so as to get at least one file that gets evaluated whatever is the invocation mecanism.
This is a quick suggestion of where to put things.
-
~/.bashrc (Gets evaluated in all occasion, provided you follow the recommendation)
For fast-evaluation environment variable and code for your user-only and bash-only command-line usage (aliases for instance). bashism are welcome.
It gets loaded on itself upon:
- make a new shell window/pane in graphical sessions.
- calling
bash
-
screen
new pane or tab. (nottmux
!) - any bash instance in a graphical console client
(
terminator
/gnome-terminal
...) if you don't tick option "run command as login shell".
And it will get loaded in all the other occasion thanks to the prior recommendation.
-
~/.bash_profile (Gets evaluated in specific occasion only)
For slow-evaluation environment variable and code for your user-only and console-session processes. bashism are welcome. It gets loaded on:
- console login (Ctrl-Alt F1),
- ssh logins to this machine,
-
tmux
new pane or windows (default settings), (notscreen
!) - explicit calls of
bash -l
, - any bash instance in a graphical console client
(
terminator
/gnome-terminal
...) only if you tick option "run command as login shell".
-
~/.profile (Gets evaluated only in graphical-session)
For slow-evaluation environment variables and with no-bashism for your user-only and all graphical-session processes. It gets loaded upon login in your graphical UI.