Обработка аргументов командной строки в префиксной нотации в Python - PullRequest
7 голосов
/ 14 мая 2010

Я пытаюсь разобрать командную строку в Python, которая выглядит следующим образом:

$ ./command -o option1 arg1 -o option2 arg2 arg3

Другими словами, команда принимает неограниченное количество аргументов, и каждому аргументу может предшествовать опция -o, которая относится конкретно к этому аргументу. Я думаю, что это называется «префиксная нотация».

В оболочке Bourne я бы сделал что-то вроде следующего:

while test -n "$1"
do
    if test "$1" = '-o'
    then
        option="$2"
        shift 2
    fi
    # Work with $1 (the argument) and $option (the option)
    # ...
    shift
done

Оглядываясь на руководства по Bash и т. Д., Это кажется принятой идиомой, поэтому я предполагаю, что Bash оптимизирован для работы с аргументами командной строки таким образом.

Пытаясь реализовать этот шаблон в Python, я сначала предположил использовать pop(), так как это в основном операция стека. Но я предполагаю, что это не сработает так же на Python, потому что список аргументов в sys.argv находится в неправильном порядке и должен обрабатываться как очередь (то есть всплывающее окно слева). Я читал, что списки не оптимизированы для использования в качестве очередей в Python.

Итак, мои идеи таковы: преобразовать argv в collections.deque и использовать popleft(), обратить argv, используя reverse() и использовать pop(), или, возможно, просто работать с самими индексами списка int.

Кто-нибудь знает лучший способ сделать это, иначе какая из моих идей будет лучшей практикой в ​​Python?

Ответы [ 6 ]

6 голосов
/ 14 мая 2010

другой модуль stdlib: argparse

p = argparse.ArgumentParser()
p.add_argument('-o', action='append')
for i in range(1, 4): p.add_argument('arg%d' % i)
args = p.parse_args('-o option1 arg1 -o option2 arg2 arg3'.split())
print args
# -> Namespace(arg1='arg1', arg2='arg2', arg3='arg3', o=['option1', 'option2'])
5 голосов
/ 14 апреля 2014

Функциональный эквивалент Python "shift" в Bourne / Bash можно получить, импортировав sys, а затем присвоив переменной sys.argv [1:], например, «арг». Затем вы можете использовать args = args [1:] для сдвига влево один раз или использовать большее число для сдвига несколько раз. Индекс аргумента будет начинаться с 0, а не с 1. Пример выше может выглядеть так:

import sys
args = sys.argv[1:]
while len(args):
    if args[0] == '-o':
        option = args[1]
        args = args[2:] # shift 2
    # Work with args[0] (the argument) and option (the option)
    # ...
    args = args[1:] # shift
5 голосов
/ 14 мая 2010

Вы можете сделать

argv.pop(0)

, который снимает первый элемент и возвращает его. Это, вероятно, неэффективно, хотя. Может быть. Я не уверен, как argv реализован под капотом. (Опять же, если эффективность , что важно, почему вы используете Python?)

Однако, более Pythonic решение состоит в том, чтобы перебирать список без выталкивания элементов. Вот так:

o_flag = False
for a in argv:
    if a == '-o':
        o_flag = True
        continue
    # do whatever
    o_flag = False

Кроме того, я думаю, что модуль optparse заслуживает упоминания; он довольно стандартный для обработки опций и аргументов в программах на Python, хотя он может быть излишним для этой задачи, поскольку у вас уже есть несколько совершенно функциональных решений.

2 голосов
/ 14 мая 2010

Нет необходимости заново изобретать колесо: модуль getopt предназначен именно для этого. Если это не соответствует вашим потребностям, попробуйте модуль optparse, который более гибкий, но более сложный.

2 голосов
/ 14 мая 2010

Что-то вроде:

for arg in sys.argv[1:]:
  # do something with arg

должно хорошо работать для вас. Если вы не ожидаете чрезвычайно большого количества аргументов, я бы выбрал любой код, который был бы наиболее простым (и не слишком беспокоился о производительности). Argv [1:] игнорирует это первое значение argv, которое будет именем скрипта.

0 голосов
/ 13 марта 2018

В python del sys.argv[1] выполняет ту же операцию, что и shift в bash. В python sys.argv есть список. Удаление элемента по индексу 1 аналогично shift в bash.

Ниже пример скрипта Python поможет пропустить -o в аргументах и ​​рассмотреть все остальные аргументы.

#!/usr/bin/python
import sys

if __name__ == '__main__':
    while len(sys.argv) > 1:
        if sys.argv[1] != "-o":
            print sys.argv[1]
        del sys.argv[1]
...