247

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?
1
  • Accepted answer mentioned "Sourcing ~/.bash_profile from ~/.bashrc is the wrong solution. It's supposed to be the other way around; ~/.bash_profile should source ~/.bashrc." How come your solution opposite to that?
    – Cloud Cho
    Sep 22, 2022 at 18:52

7 Answers 7

304

~/.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)

15
  • 7
    I've found that when opening a Terminal from the sidebar in Ubuntu 12 the ~/.profile file is not loaded.
    – jcollum
    Mar 24, 2013 at 17:20
  • 5
    @jcollum That's good. .profile should only be sourced when you log in.
    – geirha
    Mar 30, 2013 at 6:59
  • 2
    oh, opening a terminal is not the same as logging in... I was thinking logging in to the terminal.
    – jcollum
    Mar 31, 2013 at 16:53
  • 6
    Bear in mind that .profile is ignored by bash if .bash_profile exists. See my answer here and man bash for more details.
    – terdon
    Mar 11, 2014 at 0:58
  • 3
    @terdon, yes, but bash is not involved when logging in graphically, so it goes straight for .profile.
    – geirha
    Mar 11, 2014 at 8:44
65

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.

1
  • 16
    Thanks a lot for the shotp login_shell command. Awesome!!
    – Viriato
    Apr 11, 2012 at 18:26
42

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

3
  • 2
    What are the downsides to enabling this setting?
    – chrish
    Nov 15, 2017 at 14:30
  • 2
    @chris you are just loading code a little more code than necessary in a lot of occasion. It probably doesn't matter if your ~/.bash_profile is evaluating really quickly, which is probably the case. A good thing to check is to chase out any calls to other processes that are usually quite costly.
    – vaab
    Mar 8, 2018 at 4:08
  • I checked the 'Run command as a login shell' but now every time I open a terminal, I get -bash: /home/nikhil/.bash_profile: line 1: unexpected EOF while looking for matching"` -bash: /home/nikhil/.bash_profile: line 2: syntax error: unexpected end of file
    – nkhl
    Aug 4, 2020 at 17:33
18

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.

1
  • 1
    That is what I had done and it worked, but check what the guy in the bottom says, he suggests is a bad idea to put it in bashrc and put it on the profile instead. ....Hey both ways work, thanks a lot.
    – Viriato
    Apr 11, 2012 at 18:25
14

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.

5
  • On the occasions that bash does load a profile file, it will load .profile if .bash_profile does not exist.
    – muru
    Mar 8, 2018 at 4:05
  • Thank you very much for clear explanation. it helps newbies like me. In Mac Mojave , if I put variables in ~/.bashrc and do source, and then if I do env I don't see env variables set (I tried closing iTerm and re-opening). But I notice that when I installed Android studio and other apps, all those env vars were set in /.bash_profile . So When I added in /.bash_profile it worked like charm. Why is that?
    – sofs1
    Aug 18, 2019 at 1:09
  • 1
    Something that troubles me about this: say that someone puts cosmetic junk/fun things into ~/.bashrc (like screenfetch / figlet stuff etc) so that they get some output on opening a console. Then, if they run a one line shell script that does some simple thing, that is going to always hit .bashrc. Therefore, it seems crazy to put everything into .bashrc. Also, what then is the point of .bash_profile if you put everything into .bashrc? I don't get it. Linux / bash usually make sense but this is all seems a convoluted and self-contradictory mess made up by a drunk person.
    – YorSubs
    Nov 18, 2020 at 22:40
  • To be specific: • If I want code to run in both graphical and interactive login shells, where should I put that code? • If I want code to run just in graphical terminals, where should I put that code? • If I want code to only run in interactive login shells, where should I put that code? The answer seems to be "umm, bash is just a broken confusing mess, just put the code anywhere then try to insert weird connecting chains to try and make things dotsource other things". It's all really weird ... right?
    – YorSubs
    Nov 18, 2020 at 22:44
  • 1
    @YorSubs You're not wrong. The fundamental thing to understand is .bashrc is what is executed when BASH is loaded. What you do from there if up to you. I would agree with you that dotsourcing other things is unnecessary, but I believe that practice was started by developers trying to separate the generated code in the .bashrc from their custom code .bash_profile. Jan 19, 2022 at 18:38
1

When you do sudo su the shell is not executed, instead of that try with sudo su - this will load ~/.bash_profile as source by default.

0

They want you to put it in ~/.bash_aliases now

in ~/.bashrc there is this code pointing it out:

# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

1
  • Not really. It's for aliases, not for env variables. Jan 31, 2023 at 14:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .