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:

[email protected]:~/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?

  1. Use the full path – sudo /home/user/listfiles. That’s lame though, right? Let’s look at the next option.
  2. Add the script/program/command directory path to the secure_path variable in /etc/sudoers with visudo 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 run sudo some-cmd now, the PATH environment variable inherited by the command with sudo will have what you just set.
  3. Run sudo env PATH=$PATH listfiles. Here we basically run the env command with sudo to which we pass the new PATH environment variable to be set for the following command that is supposed to run (listfiles). In this case, we are setting our current non-sudo PATH in the context of sudo.
  4. Based on the previous option, you could also have an alias set on sudo like this: alias sudo='sudo env PATH=$PATH'.

Leave a Reply

Your email address will not be published. Required fields are marked *