How to set environment without sourcing .bash_profile myself every time?

14,336

TL;DR: Put your export commands in .profile instead, remove or rename .bash_profile, and log out and back in to apply your changes.

How the Per-User "profile" Files Are Used

Most desktop environments are configured, by default, so that the .profile file in your home directory is sourced when you log in graphically. It sounds like you're using Ubuntu's default desktop environment, which is GNOME with Unity. That should work.

Most Bourne-style shells will also source .profile, when invoked as a login shell. This includes bash, except that .profile is sourced only if .bash_profile and .bash_login don't exist. If .bash_profile exists, it will be used; otherwise, if .bash_login exists, it will be used; and otherwise, .profile is used.

The reason for this is so that commands that don't depend on the shell being bash, that you want to run on login, can go in .profile, and if there are bash-specific commands, you can put them in one of those other two files. Usually you would then source .profile from within .bash_profile or .bash_login.

If the only commands in .bash_profile are the ones you've shown in your question, then you don't need to use .bash_profile at all because those commands are portable across Bourne-style shells. You can then remove .bash_profile (or rename it to something like .bash_profile.old) and put those commands in .profile. They can go at the very bottom of that file, and you can back it up first if you like (reasonable names for the backup might be .profile.old or .profile.orig, but you can name the backup whatever you want because it's not actually getting used).

The absence of .bash_profile--provided .bash_login doesn't also exist--will cause .profile to be used. (.profile is probably already being used for your graphical login.)

What to Do

Remove or rename .bash_profile.

Edit .profile. It usually looks like this:

# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

You can simply add all eleven lines of code (six, if you don't count blank lines and comments) to the bottom of .profile, save the file, and log out and back in.

Optional: You Might Consider Rewriting These Assignments

Though this is entirely optional, you might want to take this opportunity to refactor your export statements. Currently you use:

### export JAVA_HOME variable
export JAVA_HOME=/usr/local/dev/jdk1.8.0_20
export PATH=$PATH:$JAVA_HOME/bin

### export M2_HOME
export M2_HOME=/usr/local/dev/maven
export PATH=$PATH:$M2_HOME/bin

### export SCALA_HOME
export SCALA_HOME=/usr/local/dev/scala-2.11.2
export PATH=$PATH:$SCALA_HOME/bin

PATH is modified three times, one time for each other variable being assigned. This is okay and might be what you want. But it is longer and (in my opinion) less self-documenting than this alternative:

# export Java, Maven, and Scala homes and add their bins to PATH
export JAVA_HOME=/usr/local/dev/jdk1.8.0_20
export M2_HOME=/usr/local/dev/maven
export SCALA_HOME=/usr/local/dev/scala-2.11.2
export PATH=$PATH:$JAVA_HOME/bin:$M2_HOME/bin:$SCALA_HOME/bin

If You Need .bash_profile For Something Else (but you probably don't)

I should note that what I have recommended is very similar to something c0rp said previously (in a comment on a post that has since been deleted):

Put all variables to ~/.profile, and source ~/.profile from ~/.bash_profile. ~/.profile gets executed automatically by the DisplayManager during the start-up process desktop session as well as by the login shell when one logs in from the textual console.

But my recommendation differs in one significant respect: since it seems to me you have no need for a .bash_profile file at all, I recommend you just move it out of the way (i.e., delete or rename it), and not bother with sourcing it in .profile.

If you do for some reason need a .bash_profile file, then you should still avoid having environment variable definitions in it (as they would only apply to bash logins, and not your graphical login).

If you have bash-specific commands that must go in a .bash_profile file, then as c0rp said you can put this line in your .bash_profile file:

. $HOME/.profile

Then .bash_profile will source .profile and the commands in .profile will get run for both bash and non-bash logins.

If Using .profile Doesn't Work

Then more troubleshooting will be necessary, but it's worth noting that:

  • Some display managers source .profile by default; some apparently don't.
  • This may also depend on desktop environment (by which I mean, on the per-DE session profiles that tell the DM how to start the graphical session).

I've heard people say that LightDM doesn't source .profile, and I think this is true at least as it is packaged in some OSes. I can't speak to the matter absolutely, but in the Ubuntu systems I've used with LightDM as the display manager, .profile has been sourced in graphical sessions and variable exports in .profile have been effective.

(It hasn't always worked for me on other OSes, such as Debian.)

If Using .profile Doesn't Work: A Quick & Dirty Alternative

If you're willing to have some redundancy in your variable definitions, you can use .pam_environment as a quick alternative.

man pam_env explains that one may define environment variables as KEY=VAL pairs in envfiles. As that manpage explains, the default systemwide envfile is /etc/environment and the default per-user envfiles are ~/.pam_environment.

So, you could make a .pam_environment file in your home directory and put something like this in it:

JAVA_HOME="/usr/local/dev/jdk1.8.0_20"
M2_HOME="/usr/local/dev/maven"
SCALA_HOME="/usr/local/dev/scala-2.11.2"
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/dev/jdk1.8.0_20/bin:/usr/local/dev/maven/bin:/usr/local/dev/scala-2.11.2/bin"

As you can see, changing anything would require you to make multiple changes, and this high level of duplication makes it hard to read and understand too. That's why I didn't recommend this way first.

The simplest and most self-documenting way in your situation is to define and export your environment variables in .profile as described above.

The EnvironmentVariables article claims it's possible to modify the value of an environment variable, and even include expansions of other environment variables, in .pam_environment, with syntax like PATH DEFAULT=${PATH}:${HOME}/MyPrograms. However, this appears entirely inconsistent with the (more) official documentation, I've tried it on multiple machines without success, and I've only ever heard of it failing for others too. I strongly suspect the wiki author(s) have confused pam_env "envfile" syntax with pam_env "conffile" syntax (to use the terms employed in man pam_env). Hopefully one of these days someone will get around to finding out for sure, and then the wiki can be edited (either for correction or clarification).

Why .bash_profile Works For This in OS X

OS X is is one of the few environments/systems where the default configuration of terminals on its default graphical desktop (i.e., Terminal.app instances) is to start the shell as a login shell rather than as a non-login shell. (Cygwin is another.)

Since each bash instance on OS X launched directly by Terminal.app (unless you've reconfigured things) acts as a login shell, .bash_profile gets sourced.

I suspect that, outside of environments accessed through Terminal.app (or a non-graphical login, such as an SSH session), exports in .bash_profile aren't applied either.

The key difference between OS X and Ubuntu when it comes to .bash_profile is that:

  • In OS X, shells launched by Terminal.app are started as login shells. Since bash is the default interactive shell in OS X (since OS X 10.3 or something), .bash_profile is sourced if it exists.

  • In Ubuntu, when you run GNOME Terminal (or another GUI terminal emulator) from within a graphical session, the shell is starts is not usually a login shell. The tasks performed by a login shell have usually already been performed (usually by the display manager) to set up the graphical session, so the idea is that there's no need to perform them again.

    It's also a bit strange to start a login shell when nothing resembling logging in has been done.

Share:
14,336

Related videos on Youtube

quartaela
Author by

quartaela

Updated on September 18, 2022

Comments

  • quartaela
    quartaela over 1 year

    When I restart Ubuntu 14.04, environment variables are set back to default and I have to run source .bash_profile every time which is very annoying. I generally keep my environment vars in .bash_profile in home directory which is at /home/buraktas. This the text of the file:

    ### export JAVA_HOME variable
    export JAVA_HOME=/usr/local/dev/jdk1.8.0_20
    export PATH=$PATH:$JAVA_HOME/bin
    
    ### export M2_HOME
    export M2_HOME=/usr/local/dev/maven
    export PATH=$PATH:$M2_HOME/bin
    
    ### export SCALA_HOME
    export SCALA_HOME=/usr/local/dev/scala-2.11.2
    export PATH=$PATH:$SCALA_HOME/bin
    

    I will appreciate any kind of response.

    • quartaela
      quartaela over 9 years
      I read this one before I asked my question. I don't think both of them are duplicate even though they are similar to each other.
    • quartaela
      quartaela over 9 years
      @EliahKagan I have 14.04 LTS Ubuntu. By the way, I checked .profile file however, it says # ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login'# exists. So, logically I have .bash_profile which should't be cause any problems.
    • quartaela
      quartaela over 9 years
      @EliahKagan Actually thanks for your answer, and I have to say that I am really new to Ubuntu. By the way, yeah I want them set all the time with or without terminal.
    • quartaela
      quartaela over 9 years
      @EliahKagan I use Ubuntu 14.04 LTS as a desktop environment. Well there is no a specific reason about using .bash_profile. At work I started to develop on OS X so I decided to learn Ubuntu as well at home. And in OS X I use .bash_profile without any problems. Thats the only reason which I am trying to use .bash_profile.
    • Eliah Kagan
      Eliah Kagan over 9 years
      I'd originally thought this was not a duplicate of that. But the main difference between my main recommendation and geirha's in the accepted answer there is that I've explicitly said to move .bash_profile out of the way to ensure .profile gets sourced even by bash. As this isn't a very big difference, I suspect this really should be considered a duplicate. (I'll still help with questions/problems with my answer here though: please let me know if you have any trouble getting it to work.)
  • quartaela
    quartaela over 9 years
    Wow! That's an awesome answer :D. However, after I copied my text lines from .bash_profile to .profile file. It didn't work. I either tried to logout and login way and source .profile. But environment variables could not be set. The interesting thing is when I write echo $M2_HOME it shows the correct path, however, when I write mvn --version it says The program 'mvn' can be found in the following packages:. Moreover, I had changed .bashrc and .bash_profile names as .old to only use .profile
  • Eliah Kagan
    Eliah Kagan over 9 years
    @quartaela I'd first put .bashrc back, as that file doesn't prevent .profile from being used, isn't specific to login shells, is specific to bash, and is often required for bash to work the way you want. I doubt putting it back would solve the PATH problem, but it could at least help avoid others. Then: Since even source .profile didn't set PATH (but other variables were set), we should look at the full and exact text of .profile. I recommend installing the pastebinit package, then run pastebinit ~/.profile and provide the URL it gives.
  • quartaela
    quartaela over 9 years
    Finally I noticed that when I installed intellij ide from ubuntu software center it installs open-jdk automatically. This idiot thing caused me hours to figure it out. :). So, your way is working without any errors. Thanks a lot again and again. Just let me ask a little question. Should I prefer to use again .profile file for define my aliases ?
  • Eliah Kagan
    Eliah Kagan over 9 years
    @quartaela Unlike env vars, aliases work only in a shell and don't inherit or export between shell instances. So .profile won't work (except in a login shell). And aliases are for interactive use--you should rarely use one in a script. The standard, and best, place for bash aliases is thus .bashrc or .bash_aliases (which Ubuntu's default .bashrc sources). I recommend .bash_aliases for aliases you've defined yourself. More info.