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

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.


Solution 1:

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.