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

  1. sudo apt-get install openjdk-6-jdk
  2. Added the following entries to ~/.bash_profile

    export JAVA_HOME=/usr/lib/jvm/java-6-openjdk
    
    export PATH=$PATH:$JAVA_HOME/bin
    
  3. Save the changes and exit

  4. Open up a terminal again and typed the following

    echo $JAVA_HOME   (blank)
    echo $PATH        (displayed, but not the JAVA_HOME value)
    
  5. 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

  1. 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.
  2. Was in this case my terminal a non-login shell?
  3. 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. (not tmux !)
    • 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), (not screen !)
    • 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.