241

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?
Jorge Castro
  • 70,934
  • 124
  • 466
  • 653
Viriato
  • 2,521
  • 2
  • 14
  • 6
  • 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 '22 at 18:52

7 Answers7

301

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

geirha
  • 45,233
  • 13
  • 70
  • 67
  • symlinks whre setup by the package by JAVA_HOME and it's addition to the PATH where not that is why I was doing what I was doing. I deleted the bash_profile and added my exports in **.profile**. Restarted my Virtual Machine and indeed I was able to do **echo $JAVA-HOME** – Viriato Apr 11 '12 at 18:24
  • 7
    I've found that when opening a Terminal from the sidebar in Ubuntu 12 the ~/.profile file is not loaded. – jcollum Mar 24 '13 at 17:20
  • 4
    @jcollum That's good. `.profile` should only be sourced when you log in. – geirha Mar 30 '13 at 06:59
  • 2
    oh, opening a terminal is not the same as logging in... I was thinking logging in _to the terminal_. – jcollum Mar 31 '13 at 16:53
  • I've found that personal additions to be sourced *each time when opening a Terminal* do get loaded when placed on `.bash_aliases`. Would that be a better solution? – Juan A. Navarro Jul 04 '13 at 08:51
  • @JuanA.Navarro that's because your `~/.bashrc` sources `~/.bash_aliases`. The few times you need to change an environment variable; update `~/.profile` or `~/.pam_environment`, then log out and back in. – geirha Jul 04 '13 at 18:59
  • 1
    I know, that's why I added my additional code there. What I wanted to do was to configure options for the terminal (e.g. the prompt), but these were not loaded if I set them on `.profile`, even after a full restart. – Juan A. Navarro Jul 04 '13 at 20:02
  • 1
    @JuanA.Navarro Ah, you mean `PS1` and `PROMPT_COMMAND` etc? Those are not environment variables, and they do indeed belong in `~/.bashrc` as they only make sense for interactive shells. – geirha Jul 04 '13 at 20:30
  • 1
    If you are using (the Ubuntu standard) Gnome Terminal, you can do Edit->Profile Preferences, go to the Title and Command tab, and check "Run command as a login shell". It will then source your .bash_profile or .profile whenever you open a terminal, as you probably expected it to. – Lambart Sep 12 '13 at 03:01
  • 5
    Bear in mind that `.profile` is ignored by bash if `.bash_profile` exists. See my answer [here](http://superuser.com/a/570323/151431) and `man bash` for more details. – terdon Mar 11 '14 at 00:58
  • 3
    @terdon, yes, but bash is not involved when logging in graphically, so it goes straight for `.profile`. – geirha Mar 11 '14 at 08:44
  • @geirha how the-structure-that-changes-state-when-you-login-from-console is called (foo-session?) and where it is to be found, opposed to merely starting an interactive shell? (in case it's called 'login' where is it to be found?) I did `man -k login` then `man 1 login` and see `/var/run/utmp/` and `login session`, however not the corresponding kernel-or-whatever structure. – n611x007 Feb 09 '16 at 11:50
  • 1
    [This flowchart](https://medium.com/@rajsek/zsh-bash-startup-files-loading-order-bashrc-zshrc-etc-e30045652f2e) states that `.bash_profile`, `.bash_login` or `.profile` are sourced with a login shell, whether the shell is interactive or not doesn't matter. Is the flowchart wrong, or should the answer be modified? – Antonin Décimo Dec 29 '20 at 15:34
  • @AntoninDécimo thanks! Took nearly 9 years for someone to notice my error. I've edited the answer. – geirha Dec 30 '20 at 21:43
  • `and the effect should be apparent next time you log in.` There's my answer! I just needed to log out and log back in for all shells being opened to have already sourced `~/.profile` before opening. – Gabriel Staples Feb 03 '23 at 00:10
64

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.

lgarzo
  • 19,532
  • 6
  • 39
  • 35
41

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

kisoku
  • 521
  • 4
  • 3
  • 2
    What are the downsides to enabling this setting? – chrish Nov 15 '17 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 08 '18 at 04: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 04 '20 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.

Florian Diesch
  • 86,013
  • 17
  • 224
  • 214
  • 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 '12 at 18:25
12

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.

vaab
  • 1,074
  • 1
  • 12
  • 19
  • On the occasions that bash does load a profile file, it will load `.profile` if `.bash_profile` does not exist. – muru Mar 08 '18 at 04: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 '19 at 01: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 '20 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 '20 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`. – Kellen Stuart Jan 19 '22 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.

Ilaiyaa...
  • 11
  • 1
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