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
#!/bin/bash ls -alh
and if you put the target directory in your
$ 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
PATH is reset to a “default” minimum path whose value can be found in
/etc/sudoers file (or one of the files in
$ 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:
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
visudocommand. 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-cmdnow, the
PATHenvironment variable inherited by the command with
sudowill have what you just set.
sudo env PATH=$PATH listfiles. Here we basically run the
sudoto which we pass the new
PATHenvironment variable to be set for the following command that is supposed to run (
listfiles). In this case, we are setting our current non-sudo
PATHin the context of
- Based on the previous option, you could also have an alias set on
alias sudo='sudo env PATH=$PATH'.