Why does my getopts fail if I specify a username?

143 views Asked by At

I am having a problem with my first functional python script that I am writing, a fully working excerpt is listed below.

My issue is that if I include the username command line option (-u or --username), it's always blank and messes up the other command line args.

For instance, if I run this with the command line arguments of -n tdelane -s 10.1.213.226 -p xxx -v, I will get this as output:

cliloc = /usr/local/bin/cli
server = 
username = Administrator
password = 
verbose = True
o = -n
a = 
cliloc = /usr/local/bin/cli
server = 
username = 
password = 
verbose = True

As you can see, once it gets to -n, it not only sets it to nothing but it also doesn't process anything else. If I take -n out, it works. Running with -s 10.1.213.226 -p xxx -v this is the output:

cliloc = /usr/local/bin/cli
server = 
username = Administrator
password = 
verbose = True
o = -s
a = 10.1.213.226
o = -p
a = xxx
o = -v
a = 
cliloc = /usr/local/bin/cli
server = 10.1.213.226
username = Administrator
password = xxx
verbose = True

Here is the part of this script which is relevant:

import subprocess, getopt, sys, re

try:
    opts, args = getopt.getopt(sys.argv[1:], "cs:np:hv",                 
        ["cli", "server", "username", "password", "help", "verbose"])

except getopt.GetoptError as err:
    print str(err)
    usage()
    sys.exit(2)

cliloc = '/usr/local/bin/cli'
server = ''
username = 'Administrator'
password = ''
verbose = True

if verbose:
    print "cliloc = %s" % (cliloc)
    print "server = %s" % (server)
    print "username = %s" % (username)
    print "password = %s" % (password)
    print "verbose = %s" % (verbose)

for o, a in opts:
    if verbose:
        print 'o = ' + o
        print 'a = ' + a
    if o == "-v":
        verbose = True
    elif o in ("-h", "--help"):
        usage()
        sys.exit()
    elif o in ("-c", "--cli"):
        cliloc = a
    elif o in ("-s", "--server"):
        server = a
    elif o in ("-n", "--username"):
        username = a
    elif o in ("-p", "--password"):
        password = a
    else:
        assert False, "unhandled option"

if verbose:
    print "cliloc = %s" % (cliloc)
    print "server = %s" % (server)
    print "username = %s" % (username)
    print "password = %s" % (password)
    print "verbose = %s" % (verbose)

Thanks in advance!

1

There are 1 answers

2
Martijn Pieters On BEST ANSWER

You configured -n to take no arguments; there is no : after it:

opts, args = getopt.getopt(sys.argv[1:], "cs:np:hv", 
#                                            ^ no colon after this option                
    ["cli", "server", "username", "password", "help", "verbose"])

Add a colon:

opts, args = getopt.getopt(sys.argv[1:], "cs:n:p:hv",                 
#                                             ^ insert colon here
    ["cli", "server", "username", "password", "help", "verbose"])

With the colon the library knows to look for an argument and tdelane doesn't end up pushing everything into the unparsed options list:

>>> import getopt
>>> import shlex
>>> args = shlex.split('-n tdelane -s 10.1.213.226 -p xxx -v')
>>> getopt.getopt(args, "cs:np:hv")
([('-n', '')], ['tdelane', '-s', '10.1.213.226', '-p', 'xxx', '-v'])
>>> getopt.getopt(args, "cs:n:p:hv")
([('-n', 'tdelane'), ('-s', '10.1.213.226'), ('-p', 'xxx'), ('-v', '')], [])

Note that the getopt module is rather.. archaic and outdated. I'd switch to using argparse instead here.