Using Sudo

There are 3 ways of using sudo to execute commands in your script. These are listed in order of usefulness and security. In most cases, you should just use a variation of sh.contrib.sudo.

sh.contrib.sudo

Because sudo is so frequently used, we have added a contrib version of the command to make sudo usage more intuitive. This contrib version is simply a wrapper around the sh.sudo raw command, but we bake in some special keyword argument to make it well-behaved. In particular, the contrib version allows you to specify your password at execution time via terminal input, or as a string in your script.

Terminal Input

Via a with context:

import sh

with sh.contrib.sudo:
    print(ls("/root"))

Or alternatively via subcommands:

import sh
print(sh.contrib.sudo.ls("/root"))

Output:

[sudo] password for youruser: *************
your_root_files.txt

In the above example, sh.contrib.sudo automatically asks you for a password using getpass.getpass() under the hood.

This method is the most secure, because it lowers the chances of doing something insecure, like including your password in your python script, or by saying that a particular user can execute anything inside of a particular script (the NOPASSWD method).

Note

sh.contrib.sudo does not do password caching like the sudo binary does. Thie means that each time a sudo command is run in your script, you will be asked to type in a password.

String Input

You may also specify your password to sh.contrib.sudo as a string:

import sh

password = get_your_password()

with sh.contrib.sudo(password=password, _with=True):
    print(ls("/root"))

Warning

This method is less secure because it becomes tempting to hard-code your password into the python script, and that’s a bad idea. However, it is more flexible, because it allows you to obtain your password from another source, so long as the end result is a string.

/etc/sudoers NOPASSWD

With this method, you can use the raw sh.sudo command directly, because you’re being guaranteed that the system will not ask you for a password. It first requires you set up your user to have root execution privileges

Edit your sudoers file:

$> sudo visudo

Add or edit the line describing your user’s permissions:

yourusername ALL = (root) NOPASSWD: /path/to/your/program

This says yourusername on ALL hosts will be able to run as root, but only root (root) (no other users), and that no password NOPASSWD will be asked of /path/to/your/program.

Warning

This method can be insecure if an unprivileged user can edit your script, because the entire script will be exited as a privileged user. A malicious user could put something bad in this script.

sh.sudo

Using the raw command sh.sudo (which resolves directly to the system’s sudo binary) without NOPASSWD is possible, provided you wire up the special keyword arguments on your own to make it behave correctly. This method is discussed generally for educational purposes; if you take the time to wire up sh.sudo on your own, then you have in essence just recreated sh.contrib.sudo.

import sh

# password must end in a newline
my_password = "password\n"

# -S says "get the password from stdin"
my_sudo = sh.sudo.bake("-S", _in=my_password)

print(my_sudo.ls("root"))

_fg=True

Another less-obvious way of using sudo is by executing the raw sh.sudo command but also putting it in the foreground. This way, sudo will work correctly automatically, by hooking up stdin/out/err automatically, and by asking you for a password if it requires one. The downsides of using _fg=True, however, are that you cannot capture its output – everything is just printed to your terminal as if you ran it from a shell.

import sh
sh.sudo.ls("/root", _fg=True)