32

I've read in a couple of places that the PATH is set in /etc/profile or the .profile file that's in the home dir.

Are these the only places that the path is set in? I want a better understanding of it.

In the /etc/profile file, as the following comment says "system-wide .profile file for the Bourne shell". Does that mean that profile files are the main configuration files for bash?

In that file I don't see the PATH var being set at all. In the .profile file in the home directory there's this line:

PATH="$HOME/bin:$PATH"

That's resetting PATH by the looks because it's concatenating the already set $PATH string with $HOME/bin: right? But if etc/profile and ~/.profile are the only files setting PATH where is $PATH coming from in that line of code if it's not defined in /etc/profile?

Can someone experienced please give a broad and detailed explanation of the PATH variable? Thanks!

  • sorry, it took years to answer. Cross-posting from https://stackoverflow.com/a/77740722/847349 :

    indeed, finding out where some part is defined requires too much effort.

    Thus, I’ve codified the heuristics into a tool:

    https://github.com/d-led/pathdebug

    pathdebug PATH and you'll get the sources, and whether the directories exist or are duplicates

    – Dmitry Ledentsov Jan 04 '24 at 18:10

5 Answers5

37

There are many places where PATH can be set.

The login program sets it to a default value. How this default value is configured is system-dependent. On most non-embedded Linux systems, it's taken from /etc/login.defs, with different values for root and for other users. Consult the login(1) manual on your system to find out what it does.

On systems using PAM, specifically the pam_env module, environment variables can be set in the system-wide file /etc/environment and the per-user file ~/.pam_environment.

Then most ways to log in (but not cron jobs) execute a login shell which reads system-wide and per-user configuration files. These files can modify the value of PATH, typically to add entries but sometimes in other ways. Which files are read depend on what the login shell is. Bourne/POSIX-style shells read /etc/profile and ~/.profile. Bash reads /etc/profile, but for the per-user file it only reads the first existing file among ~/.bash_profile, ~/.bash_login and ~/.profile. Zsh reads /etc/zshenv, ~/.zshenv, /etc/zprofile, ~/.zprofile, /etc/zlogin and ~/.zlogin. Many GUI sessions arrange to load /etc/profile and ~/.profile, but this depends on the display manager, on the desktop environment or other session startup script, and how each distribution has set these up.

7

The initial PATH variable is usually set in /etc/profile Sometimes a sys admin will also put PATH variables to source in /etc/profile.d

These are the system PATH vars that everyone who logs in inherits by default (unless over-ridden locally). This usually sets obvious paths, like /usr/bin, although at my job we use /opt and a few custom locations extensively, so those are set there as well.

On a per-user login basis accounts, PATH may also be defined in ~/.profile. That might define things that not all users have access to; maybe department heads can run binaries from /opt but other users aren't bothered with those binaries. Users can modify that file themselves, too, and the nice thing about .profile is that it is not shell-specific; if you login, the PATH set there gets sourced.

For shell-specific logins, PATH may be defined in ~/.bash_profile, ~/.bashrc, or .cshrc, or similar. Users can set PATH here if they want specific paths for specific shells, or if they just happen to maintain all their personal preferences there.

In summary: /etc/profile and /etc/profile.d are traditionally cascading settings; they get inherited and usually are added to in personal dot-files (although a user could choose to override them instead). Personal dot-files are usually set by a user.

Of course, a shell has environment variables, too, so a local environment variable can also add or override default PATH in any of the configuration files.

  • I've just checked all of those files which you mentioned, ~/.bash_profile and .cshrc do not exist however. The 3 script files in the /etc/profile.d dir: appmenu-qt5.sh, bash_completion.sh & vte.sh do not set the PATH variable either. What do you mean with "a shell has environment variables too" is the default PATH set in the binary /bin/bash program? When I terminal echo $PATH I get: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games but I don't have an idea where that all is being set really. – Larry Lawless Sep 07 '15 at 08:44
  • I think I somewhat misread your question, I thought you were asking for all the locations PATH could be set, but I think you are more interested in where PATH is initially set. For that, look at /etc/bashrc. This determines how BASH is launched, which should include all initial environment variables. On my system, /etc/bashrc reads from /etc/profile.d but it sounds like you only have 3 files in /etc/profile.d so your distro may be doing it differently. – Klaatu von Schlacker Sep 07 '15 at 20:06
  • 1
    I basically want to know the ins and outs of it. I wish Ken Thompson was my father :) – Larry Lawless Sep 08 '15 at 21:58
  • You'll get there. Believe me, after you use this stuff on a daily basis for a while, it all starts to sink in, and as long as you keep asking "why?" and reading docs for the answers, you do eventually learn a lot! – Klaatu von Schlacker Sep 08 '15 at 23:32
  • In Linux Mint 18 Cinnamon be sure to check /etc/profile.d/jdk_home.sh I renamed this file to jdk_home.sh.old and now my path does not keep getting overridden and I can call java -version and see Java 9 as expected. Even though I correctly selected Java 9 in update-aternatives --config java this jdk_home.sh file kept overriding the $PATH – flyingdrifter Dec 09 '17 at 20:22
5

To add to the other answers:

bash will set PATH to a hard-coded default value if it's not set in the environment. On an Ubuntu Server 16.04.2 machine, I get:

$ env -i bash -c 'echo $PATH'
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.

We can check that this value is indeed hard-coded, and not read from the environment or some file, using the strings utility:

$ strings /bin/bash | grep /usr/sbin
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.

However, I get a different result on my Arch Linux machine:

$ env -i bash -c 'echo $PATH'
/usr/local/sbin:/usr/local/bin:/usr/bin

So, it looks like this default is chosen at the time the bash binary was built, which depends on the OS / distribution in use.

2

Stuff, that I dont see:

  • X stuff
  • Masterfiles from where .profile etc are copied over on account creation
  • pam_env
  • A recent thread on Debian, where this is discussed in some detail.

As for Ken Thompson you may be surprised at his: "Views on Linux".

Rusi
  • 489
0

https://askubuntu.com/questions/705912/where-is-my-path-variable-being-set

^^ This helped me. Try grepping 'PATH=' or 'export PATH=' instead of the actual directory to see where it is being set

Angela
  • 1
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review – Stephen Kitt Aug 18 '22 at 06:24