How to set PATH Environment Variable for Sudo Commands (command not found error)
If you write a script or a program and put it in a folder that is present in your PATH
environment variable, then you will be able to invoke it directly with the name.
So for instance let’s say you have a silly script like this in /home/user/listfiles
:
#!/bin/bash
ls -alh
and if you put the target directory in your PATH
:
$ export PATH="$PATH:/home/user"
Then you will be able to run listfiles
from anywhere in the file system:
user@host:~/foo/bar$ listfiles
... lists files and directories insider ~/foo/bar
Most of us already know this, it’s nothing new. But there’s something that a lot of people miss in the initial days.
If the script requires sudo
privilege for some reason, then running the following will give you an error:
$ sudo listfiles
sudo: listfiles: command not found
Why is that? Because when you run a script/program/command with sudo
, the default settings set by the underlying operating system would ensure that the execution happens within a new, minimum/restricted environment for security reasons. This means not all environment variables (especially PATH
) will be inherited by the commands that you run with sudo
.
Instead, PATH
is reset to a “default” minimum path whose value can be found in /etc/sudoers
file (or one of the files in /etc/sudoers.d/
):
$ sudo cat /etc/sudoers
...
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
...
You can also simply hit sudo visudo
to open the sudoers
file in edit mode and go through the contents. A simple way to confirm the difference in the PATH
in both the sudo and non-sudo environments is by running the following commands:
$ env
...
PATH=/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/user
...
$ sudo env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
See the difference?! This is what the manual says about the secure_path
sudoers option:
secure_path
Path used for every command run from sudo. If you don’t trust the people running sudo to have a sane PATH environment variable you may want to use this. Another use is if you want to have the “root path” be separate from the “user path”. Users in the group specified by the exempt_group option are not affected by secure_path. This option is not set by default.
Alright, so what are our options to solve this?
- Use the full path –
sudo /home/user/listfiles
. That’s lame though, right? Let’s look at the next option. - Add the script/program/command directory path to the
secure_path
variable in/etc/sudoers
withvisudo
command. So it’ll end up looking like this –Defaults secure_path="[old_value]:/home/user"
. This change will take effect immediately, i.e., if you runsudo some-cmd
now, thePATH
environment variable inherited by the command withsudo
will have what you just set. - Run
sudo env PATH=$PATH listfiles
. Here we basically run theenv
command withsudo
to which we pass the newPATH
environment variable to be set for the following command that is supposed to run (listfiles
). In this case, we are setting our current non-sudoPATH
in the context ofsudo
. - Based on the previous option, you could also have an alias set on
sudo
like this:alias sudo='sudo env PATH=$PATH'
.