Processing command-line arguments in prefix notation in Python

ejm picture ejm · May 14, 2010 · Viewed 7.3k times · Source

I'm trying to parse a command-line in Python which looks like the following:

$ ./command -o option1 arg1 -o option2 arg2 arg3

In other words, the command takes an unlimited number of arguments, and each argument may optionally be preceded with an -o option, which relates specifically to that argument. I think this is called a "prefix notation".

In the Bourne shell I would do something like the following:

while test -n "$1"
do
    if test "$1" = '-o'
    then
        option="$2"
        shift 2
    fi
    # Work with $1 (the argument) and $option (the option)
    # ...
    shift
done

Looking around at the Bash tutorials, etc. this seems to be the accepted idiom, so I'm guessing Bash is optimized to work with command-line arguments this way.

Trying to implement this pattern in Python, my first guess was to use pop(), as this is basically a stack operation. But I'm guessing this won't work as well on Python because the list of arguments in sys.argv is in the wrong order and would have to be processed like a queue (i.e. pop from the left). I've read that lists are not optimized for use as queues in Python.

So, my ideas are: convert argv to a collections.deque and use popleft(), reverse argv using reverse() and use pop(), or maybe just work with the int list indices themselves.

Does anyone know of a better way to do this, otherwise which of my ideas would be best-practise in Python?

Answer

jfs picture jfs · May 14, 2010

another stdlib module: argparse

p = argparse.ArgumentParser()
p.add_argument('-o', action='append')
for i in range(1, 4): p.add_argument('arg%d' % i)
args = p.parse_args('-o option1 arg1 -o option2 arg2 arg3'.split())
print args
# -> Namespace(arg1='arg1', arg2='arg2', arg3='arg3', o=['option1', 'option2'])