Как читать / обрабатывать аргументы командной строки?

625

Я изначально программист на Си. Я видел множество трюков и «хаков», чтобы прочитать много разных аргументов.

Как программисты Python могут это сделать?

связанные с

Мартино
источник
5
Используйте docopt (см. Ответ @ ralbatross на stackoverflow.com/a/14790373/116891 ). Я пробовал все остальные пути, и, действительно, докопт - это единственный способ, которым я буду пользоваться в будущем.
Пэт
2
Я не думаю, что есть один лучший способ. argparse является стандартным и функциональным. Докопт очень элегантный, но не в стандартной библиотеке. Для очень простого и легкого использования вы можете сделать так, чтобы значения функций по умолчанию обрабатывали значения аргументов командной строки по умолчанию .
Саймон Хиббс

Ответы:

457

Каноническое решение в стандартной библиотеке argparse( документы ):

Вот пример:

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-f", "--file", dest="filename",
                    help="write report to FILE", metavar="FILE")
parser.add_argument("-q", "--quiet",
                    action="store_false", dest="verbose", default=True,
                    help="don't print status messages to stdout")

args = parser.parse_args()

argparse поддерживает (среди прочего):

  • Несколько вариантов в любом порядке.
  • Короткие и длинные варианты.
  • Значения по умолчанию.
  • Генерация сообщения об использовании.
Айман Хуриех
источник
27
Да, это лучшие. Поскольку они являются частью стандартной библиотеки, вы можете быть уверены, что они будут доступны и просты в использовании. Optparse, в частности, мощный и простой.
Барри Уарк
4
optparse - один из лучших; getopt стар и действительно должен считаться устаревшим.
jemfinch
12
на данный момент (12/2011) argparse теперь считается лучшим вариантом, чем optparse, правильно?
OOB
54
Документация Python предлагает использовать argparse вместо optparse.
earthmeLon
7
Поскольку optparseэто устарело, задающий вопрос больше не является участником переполнения стека, и это является общепринятым ответом на очень заметный вопрос - пожалуйста, рассмотрите возможность полностью переписать пример кода, чтобы argparseвместо него использовать stdlib .
Вим
548
import sys

print("\n".join(sys.argv))

sys.argv список, содержащий все аргументы, переданные сценарию в командной строке

В принципе,

import sys
print(sys.argv[1:])
Джон Славик
источник
83
Для действительно простых вещей, это путь, хотя вы, вероятно, хотите только использовать sys.argv[1:](избегая имени скрипта).
Xiong Chiamiov
128

Просто ходить по евангелизации для argparse, который лучше по этим причинам .. по существу:

(скопировано по ссылке)

  • Модуль argparse может обрабатывать позиционные и необязательные аргументы, тогда как optparse может обрабатывать только необязательные аргументы

  • argparse не является догматичным, как должен выглядеть ваш интерфейс командной строки - поддерживаются такие параметры, как -file или / file, а также обязательные параметры. Optparse отказывается поддерживать эти функции, предпочитая чистоту практичности

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

  • argparse поддерживает действие, которое использует переменное число аргументов командной строки, в то время как optparse требует, чтобы точное количество аргументов (например, 1, 2 или 3) было известно заранее.

  • argparse поддерживает парсеры, которые отправляют подкоманды, в то время как optparse требует установки allow_interspersed_argsи выполнения парсера вручную

И мой личный фаворит:

  • argparse позволяет указывать параметры типа и действия add_argument() с помощью простых вызываемых элементов, в то время как optparse требует взлома таких атрибутов класса, как STORE_ACTIONSили, CHECK_METHODSдля правильной проверки аргументов.
Silfheed
источник
27
Теперь это часть стандартного Python с 2.7 и 3.2 :)
jpswain
Что такое «необязательные аргументы»? Вы говорите, что они в optparse. Я думал, что это были аргументы, которые могут или не могут быть предоставлены, но вы сказали, что они в optparse, продолжая говорить, что «optparse требует, чтобы точное количество аргументов было известно заранее». Так что либо ваше определение «необязательного аргумента» отличается от того, что я думал, либо ваш ответ не соответствует самому себе.
ArtOfWarfare
1
Просто краткость: argparse документация также безумно, безумно сложна. Вы не можете получить простой ответ на вопрос «как заставить аргумент командной строки принимать одно значение и как получить к нему доступ». </ gripe>
osman
2
@osman Этот нежный урок по argparse может помочь ...
lifebalance
2
«Необязательные аргументы» @ArtOfWarfare в этом контексте предположительно означают аргументы, указанные с аргументами, подобными опциям, такими как -fили --foo, в то время как «точное количество аргументов должно быть известно заранее», предположительно, означают позиционные аргументы, заданные без каких-либо предшествующих флагов опций.
mtraceur
67

Существует также argparseмодуль stdlib («улучшение» в optparseмодуле stdlib ). Пример из введения в argparse :

# script.py
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'integers', metavar='int', type=int, choices=range(10),
         nargs='+', help='an integer in the range 0..9')
    parser.add_argument(
        '--sum', dest='accumulate', action='store_const', const=sum,
        default=max, help='sum the integers (default: find the max)')

    args = parser.parse_args()
    print(args.accumulate(args.integers))

Применение:

$ script.py 1 2 3 4
4

$ script.py --sum 1 2 3 4
10
JFS
источник
1
это просто копия и вставка
blitu12345
3
@ blitu12345 на момент публикации моего ответа не было никаких других ответов, в которых упоминается argparse. Сам модуль не был в stdlib¶ Что вы имеете против примеров кода из документации? Как вы думаете, почему необходимо придумывать собственные примеры вместо примеров, предоставленных автором модуля? И я не люблю ответы только на ссылки (я не одинок).
Jfs
1
Люди, приезжающие сюда, уже имели представление о том, что в документации и будут здесь только для дальнейшего прояснения темы. То же самое было в моем случае, но то, что я действительно нашел здесь, это копия и вставка из оригинальной документации.
blitu12345
2
«Люди, приезжающие сюда, уже имели представление о том, что в документации», - я очень сомневаюсь в этом предположении. как - то.
Sjas
49

Один из способов сделать это - использовать sys.argv. Это напечатает имя скрипта в качестве первого аргумента и все остальные параметры, которые вы передаете ему.

import sys

for arg in sys.argv:
    print arg
JPCosta
источник
49

Библиотека Docopt действительно гладкая. Он создает аргумент dict из строки использования для вашего приложения.

Например, из документа docopt:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)
ralbatross
источник
4
Это быстро стало моим любимым способом. Это синтаксический анализ строк, поэтому он хрупкий, но все хрупкий в одном месте, и вы можете просмотреть свою логику на try.docopt.org . Необязательные и взаимоисключающие аргументы делаются действительно элегантно.
gvoysey
4
Я отчаянно хочу увидеть остальную часть кода для naval_fate.py
Джон Лоуренс
48

Если вам нужно что-то быстрое и не очень гибкое

main.py:

import sys

first_name = sys.argv[1]
last_name = sys.argv[2]
print("Hello " + first_name + " " + last_name)

Тогда беги python main.py James Smith

произвести следующий вывод:

Привет Джеймс Смит

Кент Мунте Касперсен
источник
Более реалистичное использование было бы python main.py "James Smith"что ставит James Smithв sys.argv[1]и производит , IndexErrorкогда вы пытаетесь использовать несуществующий sys.argv[2]. Поведение цитирования будет в некоторой степени зависеть от того, с какой платформы и оболочки вы запускаете Python.
tripleee
10
Я не согласен, что мое использование менее реалистично. Притвориться, что вашей программе нужно знать точное имя и фамилию человека, чтобы запустить сценарий в бизнесе, где люди могут иметь несколько имен и фамилий? Если у Джеймса Смита в качестве дополнительного имени или фамилии указан Джозеф, как будет различаться, является ли Джозеф дополнительным именем или фамилией, если вы это делаете python main.py "James Joseph Smith"? Если вас интересует индекс за пределами границ, вы можете добавить проверку на количество предоставленных аргументов. Менее реалистично или нет, мой пример показывает, как обрабатывать несколько аргументов.
Кент Мунте Касперсен
1
Все остальные ответы предназначены для составления лунного десанта. Я просто просто использую gmail-trash-msg.py MessageID. Этот ответ прост, чтобы тестовый MessageIDпараметр был передан sys.argv[1].
WinEunuuchs2Unix
26
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]
бее
источник
19

Я сам использую optparse, но мне действительно нравится направление, в котором движется Саймон Виллисон со своей недавно представленной библиотекой optfunc . Работает:

«анализ определения функции (включая ее аргументы и их значения по умолчанию) и использование ее для создания анализатора аргументов командной строки».

Так, например, это определение функции:

def geocode(s, api_key='', geocoder='google', list_geocoders=False):

превращается в этот необязательный текст справки:

    Options:
      -h, --help            show this help message and exit
      -l, --list-geocoders
      -a API_KEY, --api-key=API_KEY
      -g GEOCODER, --geocoder=GEOCODER
Ван Гейл
источник
8

Мне нравится getopt из stdlib, например:

try:
    opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
except getopt.GetoptError, err: 
    usage(err)

for opt, arg in opts:
    if opt in ('-h', '--help'): 
        usage()

if len(args) != 1:
    usage("specify thing...")

В последнее время я добавлял к этому что-то похожее, чтобы сделать вещи менее многословными (например, сделать «-h» неявным).

Питер Эриксон
источник
8

Pocoo в щелчке более интуитивный, требует меньше шаблонного, и, по крайней мере , как мощные , как argparse.

Единственная слабость, с которой я сталкивался до сих пор, это то, что вы не можете много настраивать, чтобы помочь страницам, но обычно это не является обязательным требованием, и docopt кажется очевидным выбором, когда это так.

Райн Эверетт
источник
7

Как вы можете видеть, optparse «Модуль optparse устарел и не будет дальше разрабатываться; разработка продолжится с модулем argparse ».

tverrbjelke
источник
5
import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                   help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                   const=sum, default=max,
                   help='sum the integers (default: find the max)')

args = parser.parse_args()
print(args.accumulate(args.integers))

Assuming the Python code above is saved into a file called prog.py
$ python prog.py -h

Ref-link: https://docs.python.org/3.3/library/argparse.html
JON
источник
4

Вас может заинтересовать небольшой модуль Python, который я написал, чтобы сделать обработку аргументов командной строки еще проще (с открытым исходным кодом и бесплатное использование) - Commando

Муфаса
источник
1
Уже есть другой модуль синтаксического анализа командной строки с именем Commando: github.com/lakshmivyas/commando . Оборачивает argparse с помощью декораторов.
Роберто Бонваллет
1
повторное изобретение питона и колеса
Дерек
4

Я рекомендую смотреть на docopt как на простую альтернативу этим другим.

docopt - это новый проект, который работает, анализируя ваше сообщение об использовании --help, а не требует, чтобы вы все реализовали самостоятельно. Вы просто должны поместить свое сообщение об использовании в формате POSIX.

Дэвид С. Бишоп
источник
4

Еще один вариант это Argh . Он основан на argparse и позволяет писать такие вещи, как:

import argh

# declaring:

def echo(text):
    "Returns given word as is."
    return text

def greet(name, greeting='Hello'):
    "Greets the user with given name. The greeting is customizable."
    return greeting + ', ' + name

# assembling:

parser = argh.ArghParser()
parser.add_commands([echo, greet])

# dispatching:

if __name__ == '__main__':
    parser.dispatch()

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

круговая гибель
источник
Это лучшее решение. Использовать arghпроще, чем другие библиотеки или использовать sys.
Хуанхо Сальвадор
Мне бы хотелось, arghно он не особенно подходит для сценариев, в которых вы больше всего не хотите иметь команду с подкомандами.
tripleee
1
@tripleee YMMV, но я обнаружил, что это было скорее дефектом в документации, чем в самой библиотеке. Кажется вполне возможным иметь def frobnicate_spleches(...)определение функции, которая делает все, что делает ваш скрипт, а затем делать if __name__ == '__main__': argh.dispatch_command(frobnicate_spleches)в конце файла.
круговые крушения
0

Мое решение - entrypoint2 . Пример:

from entrypoint2 import entrypoint
@entrypoint
def add(file, quiet=True): 
    ''' This function writes report.

    :param file: write report to FILE
    :param quiet: don't print status messages to stdout
    '''
    print file,quiet

текст справки:

usage: report.py [-h] [-q] [--debug] file

This function writes report.

positional arguments:
  file         write report to FILE

optional arguments:
  -h, --help   show this help message and exit
  -q, --quiet  don't print status messages to stdout
  --debug      set logging level to DEBUG
понты
источник