* Added backward compatibility/support for python 2.3 or older.

* Added more general-purpose (some coreutils, grep, less, etc.) Linux commands
  into the namespace for ease of use in regular python.
master
wirawan 15 years ago
parent d27c00e979
commit 3a22bb1e99
  1. 104
      shell_tools.py

@ -1,4 +1,4 @@
# $Id: shell_tools.py,v 1.3 2010-01-20 17:25:54 wirawan Exp $ # $Id: shell_tools.py,v 1.4 2010-01-20 21:27:41 wirawan Exp $
# #
# wpylib.shell_tools # wpylib.shell_tools
# Created: 20100106 # Created: 20100106
@ -9,30 +9,35 @@
# #
import os import os
import subprocess import os.path
import sys import sys
try:
import subprocess
has_subprocess = True
except:
if "has_subprocess" not in globals():
print >>sys.stderr, "Newer subprocess module does not exist, using older interfaces."
has_subprocess = False
def mcd(subdir): def mcd(subdir):
# Assuming we have GNU coreutils' mkdir # Assuming we have GNU coreutils' mkdir
cmd = ["mkdir", "-p", subdir] mkdir("-p", subdir)
try:
retcode = subprocess.call(cmd, shell=False)
if retcode == 0:
os.chdir(subdir) os.chdir(subdir)
return
print >>sys.stderr, "mcd " + subdir + ": ",
if retcode < 0:
print >>sys.stderr, "mkdir was terminated by signal", -retcode
else:
print >>sys.stderr, "mkdir returned", retcode
raise RuntimeError, "Directory creation failure"
except OSError, e:
print >>sys.stderr, "mcd failed:", e
raise
def provide_file(dest, src):
"""Checks if file `dest' exists. If it does not, provide for it by means
of a softlink from `src'."""
if not os.path.exists(dest):
# strip trailing /'s just in case it exists
os.symlink(src, dest.rstrip("/"))
# Low-level utilities:
def errchk(cmd, args, retcode): def errchk(cmd, args, retcode):
"""Checking for error after the invocation of an external command."""
if retcode == 0: return if retcode == 0: return
print >>sys.stderr, "Error executing ", cmd, " ".join(args) print >>sys.stderr, "Error executing ", cmd, " ".join(args)
@ -43,12 +48,30 @@ def errchk(cmd, args, retcode):
raise RuntimeError, err raise RuntimeError, err
def quote_cmdline(seq):
"""Quotes the strings in seq for feeding to shell.
This is a severe protection to prevent:
- variable, command, or other substitutions
- shell expansions (parameter, wildcard)
- word splitting
- invocation of shell builtin (!!!)
"""
# Python 2.6's subprocess.py has list2cmdline, but I don't like it because
# it still allows the shell to interpret wildcards. We have to quote wildcards
# (*, [], {}, ?) and $ as well.
rslt = []
for i in seq:
inew = '"' + i.replace("\\", "\\\\").replace('"', '\\"').replace('$', '\\$').replace('`', '\\`') + '"'
rslt.append(inew)
return " ".join(rslt)
if has_subprocess:
def run(prg, args): def run(prg, args):
retcode = subprocess.call((prg,) + args) retcode = subprocess.call((prg,) + tuple(args))
errchk(prg, args, retcode) errchk(prg, args, retcode)
return 0 return 0
def pipe_out(args, split=False, shell=False): def pipe_out(args, split=False, shell=False):
"""Executes a shell command, piping out the stdout to python for parsing. """Executes a shell command, piping out the stdout to python for parsing.
This is my customary shortcut for backtick operator. This is my customary shortcut for backtick operator.
@ -60,9 +83,51 @@ def pipe_out(args, split=False, shell=False):
else: else:
return retval.splitlines() return retval.splitlines()
else:
def run(prg, args=()):
# Python < 2.4 does not have subprocess, so we use spawnvp
retcode = os.spawnvp(os.P_WAIT, prg, (prg,) + tuple(args))
errchk(prg, args, retcode)
return 0
def pipe_out(args, split=False, shell=False):
"""Executes a shell command, piping out the stdout to python for parsing.
This is my customary shortcut for backtick operator.
The result is either a single string (if split==False) or a list of strings
with EOLs removed (if split==True)."""
if shell or isinstance(args, str):
# BEWARE: args should be a string in this case
p = os.popen(args, "r")
else:
args = quote_cmdline(args)
p = os.popen(args, "r")
retval = p.read()
status = p.close()
if not split:
return retval
else:
return retval.splitlines()
# coreutils
# coreutils
# and other common utilities
CMD = ['cat', 'cp', 'head', 'grep', 'less', 'ls', 'mkdir', 'mv', 'rm', 'tail']
CMD_NAME = {}
for n in CMD:
CMD_NAME[n] = n
s = """def %(cmd)s(*args): run(CMD_NAME['%(cmd)s'], args)"""
exec(s % {'cmd': n })
def import_commands(namespace, cmds=None):
if cmds == None: cmds = CMD
thismod = globals()
for n in cmds:
n_act = thismod[n]
namespace.setdefault(n, n_act)
"""
def cp(*args): def cp(*args):
run('cp', args) run('cp', args)
@ -71,4 +136,5 @@ def mkdir(*args):
def mv(*args): def mv(*args):
run('mv', args) run('mv', args)
"""

Loading…
Cancel
Save