Обрабатывать несколько значений для одной опции с помощью getopt/optparse?
Можно ли получить несколько значений для одной опции, используя 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 ответов
Да, это можно сделать с помощью 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
Несмотря на утверждения других комментариев, это возможно с 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"))
Извините, что опоздал на вечеринку, но я решил это с optparse, используя флаг nargs.
parser.add_option('-c','--categories', dest='Categories', nargs=4 )
http://docs.python.org/2/library/optparse.html
Стоит также отметить, что argparse (предложенный unutbu) теперь является частью стандартного дистрибутива python, тогда как optparse устарел.
Другой вариант - определить разделитель и обработать его локально, как параметры в команде 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'
Ни 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. Если это один из ваших вариантов, обработайте его в подклассе, иначе перешлите в базовый класс.
Вы можете сделать это с 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
становится стандартным.
Проще:
make_option(
"-c",
"--city",
dest="cities",
action="append",
default=[],
help="specify cities",
)
Действие добавления - самое простое решение этой проблемы.