Обрабатываете несколько значений для одной опции с помощью getopt / optparse? - PullRequest
25 голосов
/ 05 ноября 2010

Возможно ли получить несколько значений для одной опции, используя 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 ]

14 голосов
/ 02 мая 2012

Да, это можно сделать с помощью 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

9 голосов
/ 03 мая 2014

Несмотря на утверждения других комментариев, это возможно с vanilla optparse, по крайней мере, в Python 2.7. Вам просто нужно использовать action = "append". Из документов :

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"))
8 голосов
/ 12 февраля 2013

Извините, что опоздал на вечеринку, но я решил эту проблему с помощью 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 устарел.

5 голосов
/ 05 ноября 2010

Ни getopt, ни optparse не поддерживают это из коробки. Кроме того, в режиме по умолчанию (GNU) дополнительные аргументы будут обрабатываться как перемежающиеся аргументы, то есть становятся доступными как оставшиеся аргументы в конце обработки.

Соглашение должно предусматривать повторное упоминание одного и того же аргумента, т.е.

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

Это будет поддерживаться.

Если вы абсолютно хотите, чтобы это работало так, как вы указываете (то есть оба параметра -b и -c расширяются до следующего аргумента или конца списка аргументов), вы можете взломать что-то вместе на основе optparse. Наследовать от OptionParser и переопределять _process_short_opts. Если это один из ваших вариантов, обработайте его в подклассе, иначе перейдите к базовому классу.

5 голосов
/ 05 ноября 2010

Вы можете сделать это с параметром nargs в argparse, который поставляется с Python2.7, и загружаемым здесь .

Я думаю, что это одно из улучшений, добавленных вargparse которого нет в optparse.Так что, к сожалению, я не думаю, что есть хороший способ справиться с этим с помощью optparse или getopt (который даже старше).

Быстрое и грязное решение может состоять в том, чтобы отказаться от optparse/getop/argparseи просто разберись sys.argv сам.

Или, двигаясь в обратном направлении, вы можете подумать о том, чтобы упаковать в вашу программу замороженную копию argparse (~ 88K) (переименованную в argparse_static) и импортировать ее следующим образом:

try:
    import argparse
except ImportError:
    import argparse_static as argparse

Таким образом, программа будет использовать argparse, если она установлена, и будет использовать argparse_static, если она не установлена.Лучше всего, вам не придется переписывать много кода, так как argparse становится стандартным.

4 голосов
/ 06 августа 2012

Другой вариант - определить разделитель и обработать его локально, как параметры команды 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'
3 голосов
/ 28 июля 2014

Проще:

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

Добавить действие - самое простое решение этой проблемы.

...