Some simple wrappers around the subprocess functions for use in system administration utilities that frequently need to interpolate trusted data into shell commands (e.g. filenames from directory listings, etc):
import shellcmd
return_code = shellcmd.shell_call('ls -l {}', dirname)
listing = shellcmd.check_shell_output('ls -l {}', dirname)
Each function invokes the subprocess function of the same name with shell=True
and the supplied command string. Any positional and keyword arguments provided to the call are interpolated into the command string with the str.format
method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | '''shellcmd - simple invocation of shell commands from Python'''
def shell_call(cmd, *args, **kwds):
if args or kwds:
cmd = cmd.format(*args, **kwds)
return subprocess.call(cmd, shell=True)
def check_shell_call(cmd, *args, **kwds):
if args or kwds:
cmd = cmd.format(*args, **kwds)
return subprocess.check_call(cmd, shell=True)
def check_shell_output(cmd, *args, **kwds):
if args or kwds:
cmd = cmd.format(*args, **kwds)
return subprocess.check_output(cmd, shell=True)
|
This recipe gives up some of the power and flexibility of direct subprocess invocation in favour of simpler shell style processing.
If you need access to stderr
when using check_output
then just use shell pipe redirection as necessary in the command string. Similarly, pipelining can be handled in the command strings themselves by using " | ".join(commands)
to pass everything through.
Anyone using these wrappers (or "shell=True" in general) with untrusted data will be strung up by the next security auditor that comes along. That's actually why the names of the individual functions in the recipe include the word 'shell' - to set off red flags when it comes to security audits of code that deals with untrusted input.
Finally, keep in mind that you may occasionally get odd errors if interpolated values haven't been escaped properly.
See also the sh module: http://amoffat.github.com/sh/.