在Python中将命令行参数作为元组获取

7
以下是我希望调用脚本的示例:

这里是一个关于如何调用我的脚本的例子:

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

每个输入的文件都会有与该文件相关联的2个字符串。文件的数量可以是任意多个。

为了简化,我试图得到这样的输出:

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

这是我目前的进展:

import sys, os, traceback, 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)

使用上述脚本,我只能获取第二个文件及其相关字符串:
('file2.txt', 'string3', 'string4')

如果有人能帮我编写一些代码以实现我的目标(可能使用argparse),我将不胜感激。我尝试理解argparse,但无法弄清如何继续。只有在能够继续进行我的小项目时,我才会学习。目前我卡在了参数解析阶段... 我准备设置赏金。 - bits
5个回答

14

我认为你想要使用add_argument方法的action=append参数。

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)

这将给你:

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

在命令行界面上测试:

使用:

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)

结果:

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)

1
这对于optparse也适用,所以你只需要将action='append'添加到parser.add_option中即可。 - Emilio Silva
@Emilio - 这在 optparse 上运行得非常好。非常感谢你。接受此响应。 - bits

1

argparse 支持累加器的概念,这允许您指定同一个选项多次,这可能更符合您的需求,而不是 optparse 支持的任何内容(您特别的问题是 optparse 不知道如何处理多次指定的参数,因此在命令行上“最后一个获胜”)。argparse 包含在 Python 2.7 和 3.2 中,但您应该能够 下载它 以用于任何 2.6.x 或更高版本。


0
你没有很清楚地表达你的限制,但是这段代码可以适用于任意数量的-f和其他标志。
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

刚刚进行了一次测试... 当输入不正确时,例如 -f file1.txt "string1" "string2" -f file2.txt "string3" --verbose "string4",程序会卡住。 - Tyler

0
我会以类似于之前的答案为基础,稍作调整来处理这个问题:
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)    

现在你可以通过以下方式要求输入:
-f file1.txt,string1,string2

并以以下方式解析:

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

或者将输入设计为一个字符串:

-f "file1.txt string1 string2"

并根据您的喜好进行分割。


0

如果您正在使用optparse,因为您希望与Python 2.6兼容,那么action='append'的解决方案也可以工作:

import optparse

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

演示

>>> (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')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接