A Brief Intro to the sh Package

The other day, I came across an interesting project called sh, which I believe refers to the shell (or terminal). It used to be the pbs project, but they renamed it for reasons I haven’t figured out. Regardless, the sh package is a wrapper around subprocess that allows the developer to call executables a little more simply. Basically it will map your system programs to Python functions. Note that sh only supports linux and mac, whereas pbs supported Windows too.

Let’s look at a couple of examples.

>>> from sh import ls
>>> ls

>>> ls('/home')
user_one  user_two

In the code above, I simply imported the ls “command” from sh. Then I called it on my home folder, which spits out what user folders exist there. Let’s try running Linux’s which command.

>>> import sh
>>> sh.which('python')
'/usr/bin/python'

This time we just import sh and call the which command using sh.which. In this case, we pass in the name of the program we want to know the location of. In other words, it works the same way as the regular which program does.


Multiple Arguments

What do you do if you need to pass multiple arguments to the command? Let’s take a look at the ping command to find out!

>>> sh.ping('-c', '4', 'www.google.com')
PING www.google.com (74.125.225.17) 56(84) bytes of data.
64 bytes from ord08s12-in-f17.1e100.net (74.125.225.17): icmp_seq=1 ttl=55 time=16.3 ms
64 bytes from ord08s12-in-f17.1e100.net (74.125.225.17): icmp_seq=2 ttl=55 time=15.1 ms
64 bytes from ord08s12-in-f17.1e100.net (74.125.225.17): icmp_seq=3 ttl=55 time=21.3 ms
64 bytes from ord08s12-in-f17.1e100.net (74.125.225.17): icmp_seq=4 ttl=55 time=23.8 ms

--- www.google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 15.121/19.178/23.869/3.581 ms

Here we call ping and tell it we only want a count of four. If we don’t do that, it will basically run until we tell it to stop, which hung Python on my machine.

You can actually use keyword arguments for the parameters that you pass to the called program too. Here’s an equivalent example:

>>> sh.ping('www.google.com', c='4')

This is a little counter-intuitive in that the keyword arguments come after the URL whereas in the previous example it was the reverse. However, this is more of a Python construct that something that the sh package is doing deliberately. In Python, you can’t have a keyword argument followed by a regular argument after all.


Wrapping Up

When I stumbled across this project, I thought it was a really neat idea. Is it really that much harder to just use Python’s subprocess module? Not really, but this way was a lot more fun and some might even call sh more “Pythonic”. Regardless, I think it’s worth your time to check out. There are a few other pieces of functionality that aren’t covered here, such as “baking”, so it would be a good idea to check out the project’s documentation if you want to know more about its other features.


Additional Reading