Parsing cmd line args problem

Matt Gerrans mgerrans at mindspring.com
Sat Apr 10 03:28:32 EDT 2004


"Paulo da Silva" wrote:
> I got it to work! Is there a better way?

Yup.  If you're using Python 2.3, then check out the optparse module, if an
older vesion, getopt.

I didn't like getopt that well, so slapped together something that allowed
me to access options in a script like this:

from options import opts,env,anyopt,params

if opt.verbose:
   print 'starting'

if opt.logfile:
   logfilename = opt.logfile

debug = anyopt.debug

if debug:
   print 'Running under %s's account...' % env.username

for param in params:
   dostuff(param)

# ... etc.

If an option was specified on the command line as "/o" then opt.o will be
True.   If an option was specified as "/log:test.log" then opt.log will be
"test.log".    env gives the same shortcut for environment variables and
anyopt gives a combo of the two (so if you specify /debug, or set the debug
environment variable it is turned on).    params are what remain on the
command line after removing argv[0] and all items prefixed with '/' or '-'.

The idea was to get consistent command line handling that was very quick and
easy to use.   I still like this for quick and simple scripts.   The
weakness is that it is more dynamic, so it doesn't do nifty things like
optparse, where it automatically displays command line syntax.

- Matt

FYI, below is my options.py, but you should probably learn the optparse
module, if you're on Python 2.3:

"""
Three handy instances options classes are contained herein:

1) opts     - Command line options.
2) env      - Environment 'options'.
3) anyopt   - Either command line or environment options (command line
              options).
4) params   - List of non-option command line paramters.

"""

import os,sys
from glob import glob

# These are the non-option parameters (like filenames, etc.):
params = filter(lambda a:a[0] not in '-/', sys.argv[1:])

#---------------------------------------------------------------------
#                      FindCommandLineOption()
#
#---------------------------------------------------------------------
def FindCommandLineOption( opt, caseSensitive = 0 ):
   """Finds simple (/s) and parameterized (/f:file.ext) options.
      Returns 1 if a simple option is found, returns the
      value of an option that specifies on (eg. /f:filename.ext returns
      filename.ext'.  If None is specified, it returns 1 if no parameters
      were specified."""
   result = 0
   import sys
   import string
   if caseSensitive:
      case = lambda s: s
   else:
      case = string.lower

   if opt == None:   # Special case for None; if none, then we want to
      if len(sys.argv) == 1:  # check whether there were no parameters.
         result = 1
   else:
      for i in sys.argv[1:]:
         if i[0] == '-' or i[0] == '/':
            curOpt = i[1:]
            if case(opt) == case(curOpt):
               result = 1
            elif ':' in curOpt:
               parts = string.split(curOpt,':')
               if case(opt) == case(parts[0]):
                  result = string.join(parts[1:],':') # put together the
rest of the parts
   return result

class CommandLineOptions(object):
   """Like the EnvironmentVariables object, this object gives you a clean
      and simple interface to the command line options.

      Here is how you would check for the /v (or -v) option on the
      command line:

      opts = CommandLineOptions()
      if opts.v:
         print 'You chose the verbose option!'

      And here is how you would get a file specified by /f:filename:
      if opts.f:
         if os.path.isfile(opts.f):
            filename = opts.f
         else:
            print "Who you kiddin'?  %s is not a valid file!" % opts.f
   """
   def __getattr__(self, name):
      if name == 'help' and FindCommandLineOption('?'):
         return FindCommandLineOption('?')
      return FindCommandLineOption(name)
   def __getitem__(self,name):
      return self.__getattr__(name)

opts = CommandLineOptions()

#---------------------------------------------------------------------
#                           EnvironmentVariables
#
# Need to either inject them into the current scope, or create an object
# which has a member for each var.   I like the latter, as it is cleaner,
# and will avoid hosing locals by using its own namespace.
#---------------------------------------------------------------------
class EnvironmentVariables(object):
   def x__init__(self):
      import os
      import string
      for x in os.environ.keys():
         name = string.lower( string.join(string.split(x)) )
         exec( "self." + name + "='" + os.environ[x] + "'" )
   def __getattr__(self, name):
      if os.environ.has_key(name):
         return os.environ[name]
      else:
         name = name.replace('_',' ')
         return os.environ.get(name,'')
   def __getitem__( self, key ):
      return os.environ.get(key,'')

env = EnvironmentVariables()

#---------------------------------------------------------------------
#                              AnyOption
#
# Culls options from the command line and the environment variables.
#---------------------------------------------------------------------
class AnyOption(object):
   def __getattr__(self, name):
      result = opts.__getattr__(name)
      if not result: result = env.__getattr__(name)
      return result
   def __getitem__( self, key ):
      'Allows dictionary syntax'
      result = opts[key]
      if not result: result = env[key]
      return result

anyopt = AnyOption()

#--------------------------------------------------------------------------
#                                 ArgFiles()
#
# Gets all the files specified on the command line, via wildcards.   Also
# looks for the /r or /s option, then does a recursive collecting of them.
#
# It would be a little cleaner if this were a variable, like the others,
# instead of a function, but the possibility of a mosterous task resulting
# from an innocent command line (eg. "MyProg c:\\*.*' /s") precludes that.
# So, this is a generator, allowing the caller not to get stuck in a
# long-waiting no-status display situation.
#--------------------------------------------------------------------------
def ArgFiles(args=None):
   files = []
   if args == None: args = params
   for filespec in args:
      if filespec[0] == '/': continue
      if opts.r or opts.s:
         startdir,spec = os.path.split(filespec)
         for d,subdir,files in os.walk(startdir):
            for f in glob( os.path.join( d, spec ) ):
               yield f
      else:
         for f in glob(filespec):
            yield f





More information about the Python-list mailing list