开发者

Getting command line arguments as tuples in python

Here is an example of how I would like to call my script:

python script.py -f file1.txt "string1" "string2" -f file2.txt "string3" "string4"

Every file that goes as input will have 2 strings associated with that file. There can be any number of files.

To simplify, I am trying to get a print like this:

('file1.txt', 'string1', 'string2')
('file2.txt', 'string3', 'string4')

Here is what I have so far:

import sys, os, tracebac开发者_如何学JAVAk, optparse
import time
import re
#from pexpect import run, spawn

def main ():
    global options, args

    print options.filename

    #for filename in options.filename:
    #  print filename
      #f = file(filename,'r')
      #for line in f:
      #  print line,
      #f.close()



if __name__ == '__main__':
    try:
        start_time = time.time()
        parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='$Id$')
        parser.add_option ('-f', '--file', dest='filename', help='write report to FILE', metavar='FILE', nargs=3)
        parser.add_option ('-v', '--verbose', action='store_true', default=False, help='verbose output')
        (options, args) = parser.parse_args()
        #if len(args) < 1:
        #    parser.error ('missing argument')
        if options.verbose: print time.asctime()
        main()
        if options.verbose: print time.asctime()
        if options.verbose: print 'TOTAL TIME IN MINUTES:',
        if options.verbose: print (time.time() - start_time) / 60.0
        sys.exit(0)
    except KeyboardInterrupt, e: # Ctrl-C
        raise e
    except SystemExit, e: # sys.exit()
        raise e
    except Exception, e:
        print 'ERROR, UNEXPECTED EXCEPTION'
        print str(e)
        traceback.print_exc()
        os._exit(1)

With the above script, I get only the second file and related strings:

('file2.txt', 'string3', 'string4')


I think you want to use the action=append argument of the add_argument method

import argparse

parser= argparse.ArgumentParser()
parser.add_argument ('-f', '--file', nargs=3, action='append')

files = parser.parse_args('-f file1 string1 string2 -f file2 string3 string4 -f file3 string5 string6'.split()).file

for f in files:
    print tuple(f)

gives you:

('file1', 'string1', 'string2')
('file2', 'string3', 'string4')
('file3', 'string5', 'string6')

Testing on cli:

with:

import argparse

parser= argparse.ArgumentParser(prog='Test', usage='%(prog)s -f Filename Option1 Option2 ')
parser.add_argument ('-f', '--file', nargs=3, action='append')

files = parser.parse_args().file

for f in files:
    print tuple(f)

results:

python test.py -f file1 "foo bar" "baz" -f file2 foo bar
('file1', 'foo bar', 'baz')
('file2', 'foo', 'bar')

python test.py -f file1 "foo bar" "string2" -f file2 foo bar -f file3 "foo" "bar"
('file1', 'foo bar', 'string2')
('file2', 'foo', 'bar')
('file3', 'foo', 'bar')

python test.py -f file1 "foo bar"
usage: Test -f Filename Option1 Option2
Test: error: argument -f/--file: expected 3 argument(s)


argparse supports the notion of accumulators, which allow you to specify the same option more than once, which is probably more like what you want than anything optparse supports (your particular problem is that optparse doesn't know what to do with an argument specified multiple times, so it's "last one wins" at the command line). argparse is included in Python 2.7 and 3.2, but you should be able to download it for anything 2.6.x or later.


You weren't very clear on your constraints, but this will work for any number of -fs and other flags

import getopt
import sys

args = sys.argv[1:]
tuples = []
while args:
    try:
        opts, args = getopt.getopt(args, "f:v", ["file", "verbose"])
    except getopt.GetoptError, err:
        print str(err)
        sys.exit(-1)    

    for o, a in opts:
        if o in ("-f", "--file"):
            tuples.append((a, args.pop(0), args.pop(0)))
        if o in ("-v", "--verbose"):
            print "yep, verbose"

print tuples


I would approach this similarly to the previous answer with a slight tweak:

import getopt
import sys

args = sys.argv[1:]
tuples = []
while args:
try:
    (opts, args) = getopt.getopt(args, "f:v", ["file=", "verbose"])
except getopt.GetoptError, err:
    print str(err)
    sys.exit(2)    

Now you can either require input in the following way:

-f file1.txt,string1,string2

And parse it in the following way:

for opt, arg in opts:
    if opt in ("-f", "--file"):
        tuples.append(tuple(arg.split(",")))
    if opt in ("-v", "--verbose"):
        print "yep, verbose"
print tuples

Or design the input as one string:

-f "file1.txt string1 string2"

and split on whatever strikes your fancy.


If you are using optparse because you want to remain compatible with python 2.6, the action='append' solution works, too:

import optparse

parser = optparse.OptionParser()
parser.add_option('-f', '--file', dest='filename', nargs=3, action='append')

Demonstration

>>> (opts, args)  = parser.parse_args("-f file1.txt string1 string2 -f file2.txt string3 string4".split())
>>> for fn_tuple in opts.filename:
...    print fn_tuple
('file1.txt', 'string1', 'string2')
('file2.txt', 'string3', 'string4')
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜