When you use the sudo command on Linux, the PATH you configured as a normal user is not applied and you can end up with “command not found”.
This happens especially often when you try to run a command inside Linuxbrew (Homebrew) with sudo and the command cannot be found.
This article explains how to carry your PATH environment variable over into sudo.
Why PATH changes under sudo
For security reasons, sudo resets environment variables by default.
On many distributions, secure_path is configured in /etc/sudoers, and this fixed PATH is what gets used when running sudo.
# PATH of a normal user
$ echo $PATH
/home/user/.local/bin:/usr/local/bin:/usr/bin:/bin
# PATH under sudo (it has been reset)
$ sudo sh -c 'echo $PATH'
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binBecause directories that belong to the user (such as ~/.local/bin) are not included under sudo, commands installed there can no longer be found.
Method 1: Carry the PATH over temporarily
If you want to pass the PATH just once, add an option when you run the command. [1]
Using the –preserve-env option
sudo --preserve-env=PATH your-commandYou can name only the specific environment variables you want to carry over.
Using the env command
sudo env PATH="$PATH" your-commandThis passes your current PATH straight through when running the command.
Examples
# Run mycli installed in ~/.local/bin as root
sudo --preserve-env=PATH mycli --config /etc/myapp/config.yaml
# or
sudo env PATH="$PATH" mycli --config /etc/myapp/config.yamlMethod 2: Carry the PATH over permanently in sudoers
If adding an option every time is a nuisance, change the sudoers configuration.
Steps
Start visudo (editing the file directly is dangerous, so always use visudo)
sudo visudoComment out the
secure_pathline# Before Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # After (add # at the beginning) #Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"Add the setting that carries the PATH over
Defaults env_keep += "PATH"Save and exit (
:wqin vi)
Checking after the change
$ sudo sh -c 'echo $PATH'
/home/user/.local/bin:/usr/local/bin:/usr/bin:/binIf the user’s PATH is carried over as it is, it worked.
Method 3: Add to secure_path
There is also a way to keep the existing secure_path while adding only specific directories.
sudo visudo# Edit it so that the path is appended to the existing one
Defaults secure_path="/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"With this method you can keep the security setting in place while allowing only the paths you need.
Method 4: Run with the full path
This is the approach of specifying the command by absolute path instead of relying on PATH.
# Check where the command is
$ which mycli
/home/user/.local/bin/mycli
# Run it with the full path
$ sudo /home/user/.local/bin/mycli --versionIt needs no configuration change and works reliably.
Security considerations
If you disable secure_path or allow PATH through env_keep, there is a risk of a malicious script slipping into the PATH.
| Method | Benefit | Risk |
|---|---|---|
--preserve-env=PATH | Usable only when you need it | Has to be specified every time |
env_keep += "PATH" | Permanently convenient | Carries a risk of PATH pollution |
Adding to secure_path | Limits which paths are allowed | Easy to forget to add one |
| Specifying the full path | The safest | Longer to type |
On a personal development machine env_keep is not a problem, but on a shared server or a production environment adding to secure_path or specifying the full path is recommended.
Summary: an example configuration
Here is a summary of the recommended settings for a personal development environment.
# /etc/sudoers (edit it with visudo)
#Defaults secure_path="..." # comment this out
Defaults env_keep += "PATH"With this, commands installed in your own space, such as those in ~/.local/bin or Homebrew, can also be run with sudo.