Executable Runs Without Sudo but Not With Sudo – PHP and Environment Variables


I installed xampp in my system in the location /opt/lampp. After that I added the php location to my path variable using

export PATH=$PATH:/opt/lampp/bin

So when I run php -v using terminal I get the expected output.

PHP 5.6.8 (cli) (built: Apr 20 2015 18:37:47) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies

But when I run sudo php -v I get this:

sudo: php: command not found

I don't know why this happens. Am I doing something wrong while adding it to path variable?


This question is not a duplicate of Environment variables when run with 'sudo', because in that question zetah asked how to pass arbitrary variables to a python command. They are able to execute python using sudo, but I can't execute php using sudo.

Following this answer, I added the PATH to sudo using the following command:

sudo PATH=$PATH:/opt/lampp/bin php -v

but I am getting the output as before:

sudo: php: command not found

Following this answer, I added -E to sudo, but I get the same result:

$ sudo -E php -v
sudo: php: command not found

Best Answer

Why sudo doesn't use your PATH

The reason sudo ignores your PATH variable is that it has its own secure_path, and it's fairly determined to use it.

If you sudo cat /etc/sudoers or just sudo grep secure /etc/sudoers, you'll see what this path is on your system. I have this line:

Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

The purpose of sudo's secure_path is to try to make it less likely that a user with sudo privilege will (accidentally) run dangerous code as root after their path has been modified, perhaps to include local directories.

It's possible to avoid sudo using the secure_path altogether by modifying /etc/sudoers to comment out that line, but that would be a bad idea because it removes a security measure, and it's also unnecessary because you can easily work around it in various preferable ways.

Getting sudo to use your PATH

To override the secure_path and make sudo use your PATH as currently defined, as muru commented, you can use:

sudo env PATH="$PATH" command

Note that the -E flag or merely assigning the variable do not work (on Ubuntu at least).

$ mkdir junk                            # create a test directory to add to PATH
$ echo "echo foo" > junk/useless        # create a harmless program
$ chmod u+x junk/useless                # make it executable
$ PATH="$PATH":~/junk                   # add directory to PATH

When adding to PATH, use the absolute path (the shell will expand ~ before assigning the variable). I don't need to export (and doing so does not help), because PATH is already exported, and changing its value will cause child processes to inherit the change too.

$ useless
$ sudo useless
sudo: useless: command not found
$ sudo -E useless
sudo: useless: command not found

It's often expected that this will work... man sudo says:

-E, --preserve-env
            Indicates to the security policy that the user wishes to
            preserve their existing environment variables.

But that doesn't work. The -E flag has no effect on secure_path, which is possibly a bug.

$ sudo PATH="$PATH" useless
sudo: useless: command not found

This does not affect sudo's own environment, which has been set according to the security policy, configured by /etc/sudoers. This includes env_reset and secure_path as defaults on Ubuntu, causing a minimal environment to be loaded and the PATH to be set to whatever is in secure_path.

If sudo were able to find a command called useless in one of its own path directories and run it, it would pass PATH=$PATH into its environment as demonstrated here. But it will not itself use the given value of PATH. The solution is to run:

$ sudo env PATH="$PATH" useless

This workaround uses the env command to set PATH. Unlike sudo, env uses the given variables to set the environment, then looks for the command argument and runs the command with the modified environment. As info (coreutils) env invocation says:

Modifications to PATH take effect prior to searching for command.

Setting the PATH

When you changed your PATH variable to include the directory /opt/lampp/bin, you used this command:

export PATH=$PATH:/opt/lampp/bin

This would be effective for the current shell and all the current shell's child processes, such as shells called from this shell. When you've exited this shell and all its children have exited, that modified PATH variable has been thoroughly forgotten, and when you open a new shell you will find the old PATH variable that does not include /opt/lampp/bin. For that reason, the full command suggested by muru,

sudo env PATH="$PATH:/opt/lampp/bin" php -v

would have been necessary if you were not still using a shell where you had already added /opt/lampp/bin.

To change the path permanently, you would need to edit some configuration file that modifies your user environment or is read by shells when they start up. You can add a line to assign environment variables in your ~/.profile, for example:


Then, after logging out and back in (or running source ~/.profile to see the effect immediately), you would always be able to run

php -v


sudo env PATH="$PATH" php -v

without adjusting your PATH first.

Less cumbersome alternatives

A more convenient workaround could be to make a symlink to the executable in a location that is in the secure_path and the default PATH, for example:

sudo ln -s /opt/lampp/bin/php /usr/local/bin/php

You will then not need to do anything special when calling the command with sudo, nor will you ever need to take any steps to adjust your PATH, permanently or temporarily.

If the program you are installing has a name that is the same as the name of another program that system processes may attempt to call, then give the symlink a different name, to avoid confusing those processes. You can check that the name you want to use is not already the name of some other command using the type command:

$ type php
bash: type: php: not found

So on this system I can create a command php without fear of anything going wrong, at the moment. If I install other programs that provide a php command in future, I might have to re-think my configuration.

You could also make an alias for the command and add it to your ~/.bashrc, for example:

alias sudo-php='sudo env PATH="$PATH:/opt/lampp/bin/php"'

You could then (after running source .bashrc or opening a new shell) run


instead of sudo php to run this program as root, and sudo will not claim to be ignorant of its location.

This alias would only be available in interactive shells, so it wouldn't confuse other programs.

Of course, it's possible to make an alias for just sudo to make it always use your PATH, with alias sudo='sudo env PATH="$PATH"', but that's a bad idea as it would make the system less secure.

Related Question