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?
Jorge Castro
  • 71,754
Viriato
  • 2,581
  • 3
  • 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

305

~/.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
  • 46,101
  • 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
  • 5
    @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
  • 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 '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 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
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.

lgarzo
  • 19,832
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

kisoku
  • 531
  • 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.

  • 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
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.

vaab
  • 1,084
  • 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.

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