Friday, June 6, 2003

A friend who is new to Python was complaining about the rather lacking feature set of Python's popen*() family of functions. Namely, they take a straight command line -- not a list of arguments -- and, as such, you have to escape everything yourself if you are at all interested in security, etc,etc,etc...

This is a problem that has annoyed me off and on, as well. I figured someone had to have written a shell escape function for Python. However, Google revealed nothing useful and neither did ActiveState's wonderful archive of recipes.

While searching, I did run across pexpect:

Pexpect is a pure Python module for spawning child applications; controlling them; and responding to expected patterns in their output. Pexpect works like Don Libes' Expect. Pexpect allows your script to spawn a child application and control it as if a human were typing commands.

An example:

# This connects to the openbsd ftp site and
# downloads the recursive directory listing.
import pexpect
child = pexpect.spawn ('ftp')
child.expect ('Name .*: ')
child.sendline ('anonymous')
child.expect ('Password:')
child.sendline ('')
child.expect ('ftp> ')
child.sendline ('cd pub')
child.expect('ftp> ')
child.sendline ('get ls-lR.gz')
child.expect('ftp> ')
child.sendline ('bye')

Very useful. To add to pexpect's value, the implementation is great. Not only does it "just work" and "just work" in a way that is easy to leverage in your own code, but the implementation accounts for numerous platform specific bugs and documents each one along with version information, a bug #, and/or an URL to find more information.

Internally, pexpect uses execvp() and passes arguments to the child process as an array. It will parse a regular, popen() style, command line or it can be passed an array of arguments. This addresses the need for shell escaping very cleanly.
2:23:12 PM  pontificate