136

Where is the preferred place to set the PATH envvar?

~/.profile or /etc/environment?

What is the case when PATH is set in both places? Is the end result a concatenation of both values set in those two places?

2
  • The last assignment to PATH prevails, of course. Most scripts set it explicitly at the beginning of the script.
    – AlexP
    Dec 30, 2016 at 13:50
  • 3
    See help.ubuntu.com/community/….
    – edwinksl
    Dec 30, 2016 at 13:53

6 Answers 6

151

Summary:

  • If you want to add a path (e.g. /your/additional/path) to your PATH variable for your current user only and not for all users of your computer, you normally put it at the end of ~/.profile like in one of those two examples:

    PATH="/your/additional/path:$PATH"
    PATH="$PATH:/your/additional/path"
    

    Note that the path priorities are descending from left to right, so the first path has the highest priority. If you add your path on the left of $PATH, it will have the highest priority and executables in that location will override all others. If you add your path on the right, it will have the lowest priority and executables from the other locations will be preferred.

  • However, if you need to set that environment variable for all users, I would still not recommend touching /etc/environment but creating a file with the file name ending in .sh in /etc/profile.d/. The /etc/profile script and all scripts in /etc/profile.d are the global equivalent of each user's personal ~/.profile and executed as regular shell scripts by all shells during their initialization.


More detail:

  • /etc/environment is a system-wide configuration file, which means it is used by all users. It is owned by root though, so you need to be an admin user and use sudo to modify it.

  • ~/.profile is one of your own user's personal shell initialization scripts. Every user has one and can edit their file without affecting others.

  • /etc/profile and /etc/profile.d/*.sh are the global initialization scripts that are equivalent to ~/.profile for each user. The global scripts get executed before the user-specific scripts though; and the main /etc/profile executes all the *.sh scripts in /etc/profile.d/ just before it exits.


  • The /etc/environment file normally contains only this line:

    PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
    

    It sets the PATH variable for all users on the system to this default value, which should not be changed in a major way. At least you should not remove any of the important paths like /bin, /sbin, /usr/bin and /usr/sbin from it.

    This file is read as one of the first configuration files by every shell of every user. Note that it is not a shell script. It is just a configuration file that gets parsed somehow and that may only contain environment variable assignments!

  • The ~/.profile file can contain many things, by default it contains amongst other stuff a check whether a ~/bin directory exists and adds that to the user's existing PATH variable, like this (on older Ubuntu releases prior to 16.04 -- which adds it unconditionally -- and on 18.04, which also adds "~/.local/bin"):

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

    You see that the old value of PATH gets reused here and the new path is only appended to the beginning instead of overwriting everything. When you manually want to add new paths, you should also always keep the old $PATH value somewhere in the new string.

    This initialization script is read only by the shells of the user to which it belongs, but there's another condition:

    # ~/.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 if you use the default Bash shell, you should make sure that you don't have a ~/.bash_profile or ~/.bash_login if you want the changes in ~/.profile to have an effect for your user.


For a full understanding on Environment Variables see: https://help.ubuntu.com/community/EnvironmentVariables


Related question: difference between bash.bashrc and /etc/environment file

12
  • 2
    Nowadays ~/.profile does not check for the existence of ~/bin, but it simply has the line: PATH="$HOME/bin:$HOME/.local/bin:$PATH" Dec 30, 2016 at 14:55
  • 1
    @GunnarHjalmarsson Define "nowadays", please? I'm running 16.04 and that's how it looks there.
    – Byte Commander
    Dec 30, 2016 at 14:57
  • 2
    /etc/skel/.profile in 16.04 has the line I mentioned. You apparently created your user in a previous release. Dec 30, 2016 at 15:12
  • 2
    "...executed as regular shell scripts by all shells during their initialization." I think this is misleading. Might suggest (to some) that simply opening a non-login terminal shell from the GUI desktop will execute /etc/profile, which it won't. askubuntu.com/questions/155865/… Nov 15, 2017 at 1:03
  • 2
    Could you elaborate on why you wouldn't edit and extend /etc/environment? It seems made for the job...
    – Marc
    Nov 4, 2019 at 8:14
47

This answer is mainly about the order in which environment variables like PATH are assigned when specified in different configuration files. I do also cover where you should usually set them, but the list below does not list files in the order that you should consider using them. For general information on setting PATH and other environment variables in Ubuntu, I also recommend reading EnvironmentVariables and the other answers to this question.

The preferred place to set PATH depends on which users you need to set it for and when and how you want it to be set. Part of your decision will be whether you want an environment variable set for all users or on a per-user basis. If you're not sure, then I recommend setting it for just one user (e.g., your account) rather than systemwide.

As AlexP says, the PATH environment variable will have the value it was most recently assigned. In practice, most of the time you set PATH, you include the old value of PATH in the new value, so that the previous entries are retained.

Thus, in practice, when PATH is set from multiple files, it usually contains the entries given in all the files. But that only happens because all files that set it, except the first one, usually reference the PATH variable itself, causing its old value to be included the new one.

Therefore, you are in effect asking for the order in which PATH settings in various files take effect.

Common, general-purpose places to set PATH are listed below in the order in which they take effect when a user logs in, not in the order you should typically consider using them. Each of the places listed below is a reasonable choice for setting PATH in some situations, but only a few are good choices most of the time.

In the list below, you'll see some directory names like ~/.profile. In case you're unfamiliar with tilde expansion, ~/ refers to the current user's home directory. I mainly use this syntax for compactness. It is supported in shell scripts, but not in PAM configuration files.

1. For all users: /etc/environment

PAM on Ubuntu causes environment variables listed in /etc/environment to be set, if that file exists, which by default it does. That's how environment variables for all users are most commonly set.

$ cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"

If you must set environment variables for all user accounts, rather than just your user account, then modifying that file is likely your best choice. I recommend backing it up first. One way to back up this file is to run:

sudo cp /etc/environment /etc/environment.orig

The .orig extension is not specifically required -- you can feel good about naming the backup file anything that's not confusing or already being used. (Besides .orig, .old, .backup and .bak are common.)

You can edit this file in any of the ways you might edit any other file as the root user (sudoedit /etc/enviromnment, sudo nano -w /etc/environment, gksudo gedit /etc/environment, etc.)

/etc/environment doesn't support including the old value of a variable automatically. But this is usually unnecessary, since most of the time you would set an environment variable for all users by editing /etc/environment, you would want that to be its initial value when the user logs in, anyway. The user could then change it as they like. Typically it is good for users to be able to do this.

2. For all users: /etc/security/pam_env.conf

PAM reads environment variables for all users from /etc/security/pam_env.conf, specified with the same syntax as used in per-user ~/.pam_environment files (see below).

When the same environment variable is set in both /etc/environment and /etc/security/pam_env.conf, the value in pam_env.conf is used -- even if that value is specified as DEFAULT rather than OVERRIDE.

However, when you supersede a line in environment with one in pam_env.conf, you can include the contents of the superseded value. See the section below on .pam_environment for details (since it uses the same syntax).

It's not usually necessary to edit pam_env.conf and you should be very careful if you do, since a malformed line will usually prevent all normal user accounts from logging in at all! For example, the default pam_env.conf contains the lines:

#PATH           DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
#:/usr/bin:/usr/local/bin/X11:/usr/bin/X11

This is presented as one of several examples. One of the things it illustrates is how to split an assignment across multiple lines with \. Suppose you were to uncomment just the first line, but forgot to uncomment the second line:

PATH           DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
#:/usr/bin:/usr/local/bin/X11:/usr/bin/X11

Don't do this!

I just tested that myself by accident, and it prevented any users from logging in successfully. To fix it, I had to boot in recovery mode and change it back. (Fortunately I did this on a virtual machine I use only for testing things, so it didn't cause me any trouble.)

3. For one user: .pam_environment in the user's home directory

One of the ways to set an environment variable for a single user is for that user to edit (or create) .pam_environment in their home directory. Values set in this file supersede those set in the global /etc/environment file.

.pam_environment is not part of the skeleton of files that is copied into a user's home folder when the user account is initially created. However, if you create that file in your home directory, you can use it to set environment variables like PATH. Unlike /etc/environment (but like /etc/security/pam_env.conf), the per-user .pam_environment files do support expanding the old value of an environment variable into a new one. They are not shell scripts, however, and you must use a special syntax to achieve this, which differs somewhat from the syntax you would use in a file like .profile.

For example, if you had a bin2 directory in your home directory that you wanted to add to the end of PATH, you could do that by adding this line to .pam_environment:

PATH DEFAULT=${PATH}:/home/@{PAM_USER}/bin2

See the ~/.pam_environment subsection of EnvironmentVariables (from which the above example is closely adapted), man pam_env, and man pam_env.conf for further details.

Although this was once touted as the preferred way for Ubuntu users to change or add environment variables and is still considered a reasonable and acceptable choice, you should be careful when editing .pam_environment. Like edits to the systemwide /etc/security/pam_env.conf (see above), a malformed line in a user's .pam_environment file will prevent logins from succeeding. (I have tested this -- on purpose this time.) For information about how the recommendations have evolved, see Gunnar Hjalmarsson's comments below and this ubuntu-devel discussion.

Such a mistake is much less serious, in general, than a malformed line in pam_env.conf, because it affects only one user. However, in the case of a desktop Ubuntu system with only one user account that allows logins, such a mistake while editing .pam_environment will be just as bad as a mistake editing pam_env.conf -- if you're not already logged in, you won't be able to fix it without booting in recovery mode (or from a live USB, etc.).

(If you do have other user accounts, then you can log in as another user and fix the problem. Even if they're not an administrator and cannot sudo to root, they can still run su your-account and be prompted to enter your (not their) password. The guest account, however, cannot do this, as it is prohibited from using su to take on the identity of another user.)

4. For all users: /etc/profile and files inside /etc/profile.d/

Bourne-compatible shells (including bash, the default user shell in Ubuntu) run the commands in /etc/profile when invoked as a login shell.

Ubuntu's /etc/profile ends with:

if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

This causes the commands in any file in the /etc/profile.d/ directory whose name ends in .sh to be run as well.

Most display managers cause the commands in /etc/profile (and thus files in /etc/profile.d) to be run for graphical logins too. However, not all do, and that's a significant argument in favor of using the facilities provided by PAM instead (see above) -- unless there will never be any graphical logins to this system, which might be the case, for example, if it's a server with no GUI installed.

It's traditional to set systemwide environment variables in /etc/profile, but this is often not the best choice anymore. If you cannot set an environment variable in /etc/environment, and you must set it for all users, then it's probably better to make a new file in /etc/profile.d/ than to edit /etc/profile itself. One reason for this is that, when Ubuntu is upgraded, there may be a new default /etc/profile file. Depending on how you perform the upgrade, either the old file (with your changes) will be kept, foregoing that particular updated configuration file, or you will be prompted to handle the situation.

When the same environment variable is set in both /etc/profile and one or more files in /etc/profile.d, which is performed last? This depends on whether the commands in /etc/profile that set them appear before or after the files in profile.d have been sourced (by the code I've quoted above). Commands in /etc/profile are executed in the order they appear.

/etc/profile is a shell script, and its syntax is not the same as that of the PAM configuration files discussed above. Its syntax is the same as the syntax for the per-user ~/.profile file (see below).

If you need to write code that decides whether or not to add a particular directory to PATH (and to do so for all users), you won't be able to use /etc/environment or /etc/security/pam_env.conf to do that. This is perhaps the main situation where it is better to to use /etc/profile or /etc/profile.d/ instead.

5. For one user: .bash_profile in the user's home directory

If a user has ~/.bash_profile, bash uses it instead of ~/.profile or ~/.bash_login (see below). You should not usually have a .bash_profile in your home directory.

If you do, it usually ought to contain a command to source ~/.profile (e.g., . "$HOME/.profile"). Otherwise, the contents of the per-user .profile file aren't run at all.

6. For one user: .bash_login in the user's home directory

If a user has ~/.bash_login, bash uses it instead of ~/.profile (see below), unless ~/.bash_profile exists, in which case neither of the others will be used unless sourced from `~/.bash_login.

As with .bash_profile, you should not usually have a .bash_login file in your home directory.

7. For one user: .profile in the user's home directory.

When a Bourne-style shell is run as a login shell, it runs the commands in /etc/profile (which typically includes commands that cause the commands in files in /etc/profile.d/ to be run -- see above). After that, it runs the commands in .profile in the user's home directory. This file is separate for every user. (Bash actually runs .bash_profile or .bash_login instead if they exist -- but, for users on an Ubuntu system, those files rarely should or do exist. For details, see above and 6.2 Bash Startup Files in the Bash manual.)

~/.profile is thus the main place for user to put commands that run when they log on. It is the traditional place for you to set your PATH, but since Ubuntu has the pam_env module and supports ~/.pam_environment, you should consider using that.

As with /etc/profile, not all display managers run this file for graphical logins, though most do. This is a reason to prefer ~/.pam_environment for setting environment variables (much as one may prefer /etc/environment to /etc/profile).

You can expand environment variables, including PATH itself, when you set PATH in .pam_environment (see above). However, if you need to set PATH in a more sophisticated way, you might have to use your .profile instead. In particular, if you want to check if a directory exists every time a user logs in and only add it to PATH if it does, then you won't be able to use your .pam_environment file to add that directory to your PATH.

For example, the default per-user .profile file on Ubuntu used to end with:

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

See Gunnar Hjalmarsson's comment on Byte Commander's answer for details.

This checks if you have a bin subdirectory of your home directory. If so, it adds that subdirectory to the beginning of your PATH.

That list omits some possibilities.

There are other ways environment variables are set when users log in that depend more heavily on the type of login. For example, you may occasionally have environment variables that get set just for graphical logins or just for SSH-based remote logins. The list above does not cover such cases.

I've left out a few files where people sometimes define environment variables, like ~/.bashrc and /etc/bash.bashrc, because they are not generally recommended places to set PATH and it is rare that you should actually use them for this purpose. If you use these files to add directories to PATH, then they will sometimes be added many times and is very confusing when you examine $PATH. (In extreme cases this may slow things down, but usually it's just a matter of keeping everything clean and understandable.)

Since bash is Ubuntu's default login shell for users, and most users use it or some other POSIX-compatible shell, I've omitted information about how environment variables are set in other, non-Bourne-style shells such as tcsh.

7
  • 2
    [comment #1 of 2] Thanks for this extensive description! (I did a minor edit.) However, I have doubts as regards the recommended way(s). A few years ago EnvironmentVariables mentioned /etc/environment/~/.pam_environment as the recommended files. After having consulted with the developers I changed it to be neutral between PAM and /etc/profile.d/*.sh/~/.profile, and I still tend to look at it that way. Dec 31, 2016 at 0:19
  • 2
    [comment #2 of 2] You mentioned a couple of arguments in favor of PAM. Important arguments in favor of /etc/profile.d/*.sh/~/.profile are that the syntax is simpler and that lightdm/gdm are forgiving in case of errors (not even syntax errors prevent you to log in, but just result in warning messages). Dec 31, 2016 at 0:20
  • When you say pam_env.so, did you mean pam_env.conf? May 24, 2019 at 16:28
  • @JohanBoulé Yes, I did mean pam_env.conf. Thanks! I've edited to fix it. May 27, 2019 at 0:56
  • In #4, shouldn't "Ubuntu's /etc/profile.d ends with:" be just "Ubuntu's /etc/profile ends with:"?
    – DK Bose
    Jun 9, 2020 at 11:24
5

/etc/environment file is not a script file you can't use export there and it doesn't support variable expansion of the type $HOME, just simplevariable=value pairs. So to use that file, you'd need to simply append your path to the existing definition , is specifically meant for system-wide environment variable settings. one per line. Specifically, this file stores the system-wide locale and path settings.

~/.profile - This file gets executed whenever a bash shell is executed,is usually the recommended one for environment variables,however it has the disadvantage of only being invoked by login shells, so in order to get it to take effect you will need to log out and back in - or at least, start a new login shell.

0
2

The preferred place to set environmental variables depends on several things:

  1. Are you the only one using the computer:
    • In this case the best place to set it would be in the /etc/environment since there is no danger of _unauthorized access.
  2. If the system is used by many
    • If the variables should be accessed by all then the location would be /etc/environment, but
    • if individual users should have selected access to them then each should set theirs in the ~/.profile pertaining to each user of the system since it's located in each users home directory.

The system will read /etc/environment before reading ~/.profile. No concatenation occurs and like Alex P said the last assignment to path prevails.

For more detailed look at the factors that determine how ~/.profile and /etc/environment play out with other such locations go here and here, as these factors will influence how you use these locations.

0
0

bash reads these files, but zsh does not:

  1. system-wide

    /etc/profile - It's not a good idea to edit it directly.
    /etc/profile.d/*.sh - sourced by /etc/profile

  2. session-wide

    ~/.profile

https://help.ubuntu.com/community/EnvironmentVariables#A.2Fetc.2Fprofile.d.2F.2A.sh

-1

Check your /etc/environment file. It should contain only literal path i.e it should not contain something like "$PATH=$PATH:<any_path_you_want_to_add>".

That will cause an error into your system and make you stuck in the login loop.

You must log in to answer this question.

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