How does `sudo` search the path for executables?

I am using rubygems (1.3.7) with gems that require root privileges on Ubuntu 10.10. When I compare my setup to an ubuntu 9.10 with rubygems 1.3.6 installation, I see the following difference in gem environment:

1.3.7 / 10.10 - EXECUTABLE DIRECTORY: /var/lib/gems/1.8/bin

1.3.6 / 09.10 - EXECUTABLE DIRECTORY: /usr/bin

The output is the same whether I use sudo or not. To fix this (I don't know why it is different in the first place), I tried to modify my path variable.

My question is, where does sudo look for executables? If I install a gem (using sudo) the executable is placed in the /var path obviously. I added this path to my ~/.profile and /etc/environment files, but I cannot get sudo to execute the executables.

If I run:

  • $ gemname it runs my tool correctly.
  • $ sudo gemname it merely tells me command not found.
  • $ sudo echo $PATH it does show the correct path.
  • $ sudo -i gemname it runs correctly.
  • $ sudo sudo -V shows that the PATH is preserved.

Does sudo honour ~/.profile and/or /etc/environment? If so, they why can't it find my executable while the directory is shown in the $PATH environment variable?

I have read the documentation of sudo, I also search and looked through a ton of topics on stackoverflow and serverfault (for instance How to override a PATH environment variable in sudo?, but my example shows that $PATH contains the correct path), but they never actually show how to run a gem via sudo.


Note that, in your third command, your shell expands $PATH before sudo gets to see it, and so the output is your shell's path, not the PATH that sudo sees. What you want is something like sudo echo \$PATH or sudo sh -c 'echo $PATH'.

Beyond that, take a look at the SECURITY NOTES section of the sudo(8) man page. I believe that Ubuntu builds sudo with the SECURE_PATH build option. Look for the "Value to override user's $PATH with" line in the output of sudo sudo -V.

sudo -i simulates an initial login, and so will read files like .profile (though which files it reads depends on what root's shell is). Without -i, it inherits the preserved environment variables from its caller's environment, with the PATH sanitation I mentioned above.

As for why the path changed in the first place, I suspect that the change was a deliberate choice on the part of the developers. See more discussion on bugs.debian.org.


Let's go by parts:

  • gemname it runs my tool correctly.

That's ok :)

  • sudo gemname it merely tells me command not found.

gemname is not in your $PATH

  • sudo echo $PATH it does show the correct path.

That's a cool one: variable expansion happens before bash runs the program. So when you run this, it expands to your user $PATH before calling sudo, so the line that is passed to sudo is more like:

$ sudo echo "/usr/bin:/bin:"
  • sudo -i gemname it runs correctly.

sudo -i runs as a login shell and honors .profile and/or .login. As by the man page says:

It also initializes the environment, leaving DISPLAY and TERM unchanged, setting HOME, MAIL, SHELL, USER, LOGNAME, and PATH, as well as the contents of /etc/environment on Linux and AIX systems. All other environment variables are removed.