Як читати / обробляти аргументи командного рядка?


623

5
Використання docopt (див @ ralbatross відповідають на stackoverflow.com/a/14790373/116891 ). Я пробував усі інші способи, і, дійсно, docopt - це єдиний, який я буду використовувати вперед.
Пт

2
Я не думаю, що існує один найкращий спосіб. argparse є стандартним та функціональним. docopt дуже елегантний, але не є в стандартній бібліотеці. Для дуже легкого легкого використання ви можете зробити значення значень за замовчуванням для функції обробляти параметри аргументу командного рядка для вас .
Саймон Хіббс

Відповіді:


456

Канонічне рішення в стандартній бібліотеці: argparse( docs ):

Ось приклад:

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 є потужним і простим.
Barry Wark

4
optparse - один з найкращих; getopt старий і його справді слід вважати застарілим.
jemfinch

12
На даний момент (12/2011) аргпарсе вважається кращим варіантом, ніж optparse, правда?
OOB

54
Документація Python пропонує використовувати argparse замість optparse.
земляLon

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 може обробляти позиційні та необов'язкові аргументи, тоді як 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для правильної перевірки аргументів

27
Тепер це частина стандартного Python на 2.7 та 3.2 :)
jpswain

Що таке "необов'язкові аргументи"? Ви кажете, що вони в оптимізмі. Я подумав, що це аргументи, які можуть бути, а можуть і не бути надані, але ви сказали, що вони перебувають у optparse, продовжуючи говорити, що "optparse вимагає, щоб заздалегідь була відома точна кількість аргументів". Отже, або ваше визначення "необов'язкового аргументу" відрізняється від того, що я думав, або ваша відповідь не відповідає самій собі.
ArtOfWarfare

1
Просто захоплення: документація argparse також шалено, шалено складна. Ви не можете отримати просту відповідь на те, "як я змушу аргумент командного рядка приймати одне значення та як отримати доступ до цього значення". </gripe>
осман

2
@osman Цей ніжний підручник з аргументацією може допомогти ...
життєвий баланс

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

1
це лише копія та вставка
blitu12345

3
@ blitu12345 на момент публікації моєї відповіді не було інших відповідей, які б жодним чином згадували аргументацію. Сам модуль не був у stdlib¶ Що ви маєте проти прикладів коду з документації? Чому, на вашу думку, потрібно придумати власні приклади замість прикладів, наданих автором модуля? І мені не подобаються відповіді лише на посилання (я не один).
jfs

1
Люди, що приїжджають сюди, вже мали уявлення про те, що є в документації, і будемо тут тільки для подальшого розгляду теми. Я був моїм випадком, але те, що я дійсно знайшов тут, - це копія та вставка з оригінальних docs.Peace!
blitu12345

2
"Люди, що приїжджають сюди, вже мали уявлення про те, що є в документації", - я дуже сумніваюся в цьому припущенні. якось.
sjas

49

Один із способів зробити це - використання sys.argv. Це надрукує ім'я скрипта як перший аргумент та всі інші параметри, які ви передаєте до нього.

import sys

for arg in sys.argv:
    print arg

49

Бібліотека docopt дійсно гладка. Він будує набір аргументів із рядка використання для вашої програми.

Напр. Із readme докопта:

"""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)

4
Це швидко стало моїм улюбленим шляхом. Це сильний розбір рядків, таким чином він є крихким, але він крихкий в одному місці, і ви можете переглянути свою логіку на try.docopt.org . Необов’язкові та взаємовиключні аргументи робляться по-справжньому елегантно.
гвойсей

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.
трійка

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):

перетворюється на цей довідковий текст optparse:

    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 ."


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

4

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


1
Вже є ще один модуль розбору командного рядка з назвою Commando: github.com/lakshmivyas/commando . Він завершує аргументацію за допомогою декораторів.
Роберто Бонвальлет

1
Повторний винахід пітона та колеса
Дерек

4

Я рекомендую розглянути docopt як просту альтернативу цим іншим.

docopt - це новий проект, який працює, аналізуючи повідомлення про використання --help, а не вимагаючи від вас все реалізовувати самостійно. Вам просто потрібно розмістити повідомлення про використання у форматі POSIX.


4

Ще один варіант - argh . Він ґрунтується на аргументації та дозволяє писати такі речі:

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()

Він автоматично генерує довідку тощо. Ви можете використовувати декоратори, щоб отримати додаткові вказівки щодо того, як повинен працювати аргумент.


Це найкраще рішення. Використовувати arghпростіше, ніж інший ліб або використовувати sys.
Хуанхо Сальвадор

Мені хотілося сподобатись, arghале це не особливо підходить для сценаріїв, де ваше максимальне бажання - не мати команди з підкомандами.
трійка

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.