使用getopt / optparse为一个选项处理多个值?

时间:2010-11-05 19:44:08

标签: python getopt

是否可以使用getopt或optparse为一个选项获取多个值,如下例所示:

./hello_world -c arg1 arg2 arg3 -b arg4 arg5 arg6 arg7

请注意,每个选项(-c,-b)的实际值数可以是1或100.我不想使用: ./hello_world -c "arg1 arg2 arg3" -b "arg4 arg5 arg6 arg7"

在我看来,这可能是不可能的(也许违反了POSIX),如果我错了,请纠正我。

我见过这样的例子,可以收集行尾(./hello_world -c arg1 -b arg1 arg2 arg3)的所有非选项...但不是第一个选项。

我希望我的应用程序能够在不同的Python版本的平台上运行,所以我没有看过argparser。

7 个答案:

答案 0 :(得分:14)

是的,可以使用optparse来完成。

这是一个例子:

./test.py --categories=aaa --categories=bbb --categories ccc arg1 arg2 arg3

打印:

arguments: ['arg1', 'arg2', 'arg3']
options: {'categories': ['aaa', 'bbb', 'ccc']}

以下完整的工作示例:

#!/usr/bin/env python

import os, sys
from optparse import OptionParser
from optparse import Option, OptionValueError

VERSION = '0.9.4'

class MultipleOption(Option):
    ACTIONS = Option.ACTIONS + ("extend",)
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)

    def take_action(self, action, dest, opt, value, values, parser):
        if action == "extend":
            values.ensure_value(dest, []).append(value)
        else:
            Option.take_action(self, action, dest, opt, value, values, parser)


def main():
    PROG = os.path.basename(os.path.splitext(__file__)[0])
    long_commands = ('categories')
    short_commands = {'cat':'categories'}
    description = """Just a test"""
    parser = OptionParser(option_class=MultipleOption,
                          usage='usage: %prog [OPTIONS] COMMAND [BLOG_FILE]',
                          version='%s %s' % (PROG, VERSION),
                          description=description)
    parser.add_option('-c', '--categories', 
                      action="extend", type="string",
                      dest='categories', 
                      metavar='CATEGORIES', 
                      help='comma separated list of post categories')

    if len(sys.argv) == 1:
        parser.parse_args(['--help'])

    OPTIONS, args = parser.parse_args()
    print "arguments:", args
    print "options:", OPTIONS

if __name__ == '__main__':
    main()

http://docs.python.org/library/optparse.html#adding-new-actions

的更多信息

答案 1 :(得分:9)

尽管有其他评论的说法,但这可能是vanilla optparse,至少从python 2.7开始。你只需要使用action ="追加"。来自docs

parser.add_option("-t", "--tracks", action="append", type="int")

如果在命令行中看到-t3,则optparse相当于:

options.tracks = []
options.tracks.append(int("3"))

如果稍后会看到--tracks = 4,它会:

options.tracks.append(int("4"))

答案 2 :(得分:8)

很抱歉来参加聚会,但我刚用optparse使用nargs标志解决了这个问题。

parser.add_option('-c','--categories', dest='Categories', nargs=4 )

http://docs.python.org/2/library/optparse.html#optparse.Option.nargs

值得注意的是,argparse(由unutbu建议)现在是标准python发行版的一部分,而optparse已被弃用。

答案 3 :(得分:5)

您可以使用Python2.7附带的nargs中的argparse参数执行此操作,并可下载here

我认为这是argparse中添加的改进之一,而不是optparse。所以,遗憾的是,我认为使用optparsegetopt(甚至更早)处理此问题的方法并不好。

快速而肮脏的解决方案可能是放弃optparse/getop/argparse而只是自己解析sys.argv

或者,在相反的方向上,您可以考虑使用您的程序打包argparse(~88K)的冻结副本(重命名为argparse_static),以及 像这样导入它:

try:
    import argparse
except ImportError:
    import argparse_static as argparse

这样,如果安装了程序,程序将使用argparse,如果不是,则使用argparse_static。最重要的是,当argparse成为标准时,您不必重写太多代码。

答案 4 :(得分:5)

getopt和optparse都不支持开箱即用。此外,在默认(GNU)模式下,附加参数将被视为散布的args,即在处理结束时可用作剩余参数。

惯例是要求反复提及相同的论点,即

./hello_world -c arg1 -c arg2 -c arg3 -b arg4 -b arg5 -b arg6 -b arg7

这将得到支持。

如果你绝对希望以你指定的方式使它工作(即-b和-c都延伸到下一个参数或参数列表的结尾),那么你可以根据optparse一起破解一些东西。从OptionParser继承,并覆盖_process_short_opts。如果它是您的选项之一,请在子类中处理它,否则转发到基类。

答案 5 :(得分:4)

另一种选择是定义一个分隔符并在本地处理它,就像mount命令中的选项一样。

例如,如果,可以用作分隔符:

...
args, _ = getopt.getopt(sys.argv[1:],'b:')
for flag, arg in args:
  if flag=='-b': all_arguments = arg.split(',')
...

$ ./test -b opt1,opt2,opt3

同样的空间!但是,您的用户必须正确引用它。

$ ./test -b 'opt1 opt2 opt3'

答案 6 :(得分:3)

更容易:

make_option(
    "-c",
    "--city",
    dest="cities",
    action="append",
    default=[],
    help="specify cities",
)

Append action是解决此问题的最简单方法。