Building Command Line Utilities with Python: Page 2

(Page 2 of 2)

I process the results from the command line by calling parse_args() on the parser object. This method returns a tuple of two objects: an object that contains the options, and another that contains the arguments. The options are the result of how the script handles the -t, --true, -v, and --value that users may pass in. The options object is a pretty simple object. It stores the values from parsing the command line arguments based on the rules given to the option parser. You access the values by using standard dotted notation (options.value). The arguments object is simply a list of all the arguments not handled by one of the options.

Here is a series of calls to the script with the output of the options.

$ ./
OPTIONS:: {'true': False, 'value': None}
ARGS:: []
$ ./ --true
OPTIONS:: {'true': True, 'value': None}
ARGS:: []
$ ./ -t
OPTIONS:: {'true': True, 'value': None}
ARGS:: []
$ ./ --value=foo
OPTIONS:: {'true': False, 'value': 'foo'}
ARGS:: []
$ ./ --value foo
OPTIONS:: {'true': False, 'value': 'foo'}
ARGS:: []
$ ./ -v foo
OPTIONS:: {'true': False, 'value': 'foo'}
ARGS:: []

Calling the script with no arguments resulted in the true attribute being set to False (since that was the default) and the value attribute being set to None (since there was no default for it). Passing in either --true or -t sets the true attribute to True. Passing in either --value=foo, --value foo, or -v foo sets the value attribute to foo.

Here is a more real-world example. This is a very basic find utility. It walks a directory tree looking for things that you specify on the command line.

#!/usr/bin/env python

from optparse import OptionParser
import os

file_types = ['f', 'd']

def match_files(file_list, dirpath, pattern, ls, file_type, show_type):
    for f in file_list:
        if pattern in f:
            file_path = os.path.join(dirpath, f)
            if ls:
                os.system('ls -ld "%s"' % file_path)
                if show_type:
                    print file_type,
                print file_path

usage = "usage: %prog [options]"

parser = OptionParser(prog='pyfind', usage=usage)

parser.add_option('-t', '--type', dest='file_type', action='append', 
    help='the type of file to search for, limited to %s' % ', '.join(file_types),

parser.add_option('-n', '--name', dest='pattern', action='store', 
    help='match the file by name using the specified pattern')

parser.add_option('-l', '--ls', dest='list', action='store_true', 
    help='do a long file listing on on each matching file')

parser.add_option('-s', '--show_type', dest='show_type', action='store_true', 
    help='show file type in output')

parser.add_option('-v', '--verbose', dest='verbose', action='store_true', 
    help='verbose (for debugging)')

parser.set_defaults(file_type=[], pattern='', list=False, show_type=False)

options, args = parser.parse_args()

for d in args:
    if options.verbose:
        print 'Walking', d
    for dirpath, dirs, files in os.walk(d):
        if options.verbose:
            print dirpath, dirs, files
        pattern = options.pattern
        ls = options.list
        file_type = options.file_type
        show_type = options.show_type
        if 'f' in options.file_type:
            match_files(files, dirpath, pattern, ls, 'f', show_type)
        if 'd' in options.file_type:
            match_files(dirs, dirpath, pattern, ls, 'd', show_type)
    if options.verbose:
        print 'Done walking', d

Here is an example of running this script in the same directory that all of the scripts in this article are contained in.

$ ./ --name py --type f .

This run looked for files that contain "py" in the name. One of the useful options on the UNIX find utility is -ls, which does an ls -l on each file that matches its find criteria. I built a similar functionality into this script:

$ ./ --name py --type f --ls .
-rw-------  1 jmjones  staff  12288 Oct 31 05:40 ./
-rw-r--r--  1 jmjones  staff  12288 Oct 31 06:00 ./
-rw-r--r--  1 jmjones  staff  12288 Oct 31 05:58 ./
-rw-r--r--  1 jmjones  staff  12288 Oct 31 05:07 ./
-rwxr-xr-x  1 jmjones  staff  60 Oct 30 22:32 ./
-rwxr-xr-x  1 jmjones  staff  1896 Oct 31 05:59 ./
-rwxr-xr-x  1 jmjones  staff  1084 Oct 31 04:59 ./
-rwxr-xr-x  1 jmjones  staff  505 Oct 31 05:05 ./

I'll leave it as an exercise to the interested reader to see how I sent the options from the command line to the code that walks the directory tree. It's really not that complicated.

Building usable, useful command line utilities is a skill worth honing. But if building tools in Python is what you're interested in, don't waste your time trying to come up with a new method for parsing command line arguments. I think I've shown that optparse in the Python standard library is more than sufficient for most command line utility tasks you'll find yourself working on.

It will save you a headache and a bunch of redundant code.

This article was first published on

Page 2 of 2

Previous Page
1 2

Tags: Python, IT, Unix, call, proxy

0 Comments (click to add your comment)
Comment and Contribute


(Maximum characters: 1200). You have characters left.