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

22 ответа

Решение

Каноническое решение в стандартной библиотеке 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 поддерживает (между прочим):

  • Несколько вариантов в любом порядке.
  • Короткие и длинные варианты.
  • Значения по умолчанию.
  • Генерация сообщения об использовании.
import sys

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

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

В принципе,

import sys
print(sys.argv[1:])

Просто ходить по евангелизации для 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 чтобы получить правильную проверку аргументов

Существует также argparse модуль stdlib ("улучшение" на stdlib's optparse модуль). Пример из введения в 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

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

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

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

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

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

import sys

for arg in sys.argv:
    print arg

Библиотека 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)
#set default args as -h , if no args:
if len(sys.argv) == 1: sys.argv[1:] = ["-h"]

Я сам использую 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

Мне нравится 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" неявным).

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

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

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

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

Еще один вариант это 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.

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

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

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

Также с python3 вам может быть удобно использовать Extended Iterable Unpacking для обработки необязательных позиционных аргументов без дополнительных зависимостей:

try:
   _, arg1, arg2, arg3, *_ = sys.argv + [None] * 2
except ValueError:
   print("Not enough arguments", file=sys.stderr) # unhandled exception traceback is meaningful enough also
   exit(-1)

Выше argv распаковать делает arg2 и arg3 "необязательные" - если они не указаны в argv, они будут None, а если первое не указано, будет выдана ValueError:

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    _, arg1, arg2, arg3, *_ = sys.argv + [None] * 2
ValueError: not enough values to unpack (expected at least 4, got 3)

Причина нового ответа:

  1. В существующих ответах указано несколько вариантов.
  2. Стандартным вариантом является использование , в нескольких ответах приведены примеры из документации, а в одном ответе указано его преимущество. Но все не могут адекватно / четко объяснить ответ на фактический вопрос ОП, по крайней мере, для новичков.

Примерargparse:

      import argparse


def load_config(conf_file):
    pass


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    //Specifies one argument from the command line
    //You can have any number of arguments like this
    parser.add_argument("conf_file", help="configuration file for the application") 
    args = parser.parse_args()
    config = load_config(args.conf_file)

Вышеуказанная программа ожидает файл конфигурации в качестве аргумента. Если вы предоставите его, он будет выполнен счастливо. Если нет, он напечатает следующее

      usage: test.py [-h] conf_file
test.py: error: the following arguments are required: conf_file
  • У вас может быть возможность указать, является ли аргумент необязательным.

  • Вы можете указать ожидаемый тип аргумента, используяtypeключ

    parser.add_argument("age", type=int, help="age of the person")

  • Вы можете указать значение по умолчанию для аргументов, указавdefaultключ

Этот документ поможет вам понять это до определенной степени.

      import sys

# Command line arguments are stored into sys.argv
# print(sys.argv[1:])

# I used the slice [1:] to print all the elements except the first
# This because the first element of sys.argv is the program name
# So the first argument is sys.argv[1], the second is sys.argv[2] ecc

print("File name: " + sys.argv[0])
print("Arguments:")
for i in sys.argv[1:]:
    print(i)

Назовем этот файл command_line.pyи запустим:

      C:\Users\simone> python command_line.py arg1 arg2 arg3 ecc
File name: command_line.py
Arguments:
arg1
arg2
arg3
ecc

Теперь давайте напишем простую программу, sum.py:

      import sys

try:
    print(sum(map(float, sys.argv[1:])))
except:
    print("An error has occurred")

Результат:

      C:\Users\simone> python sum.py 10 4 6 3
23

Это обрабатывает простые переключатели, переключатели значений с необязательными альтернативными флагами.

      import sys

# [IN] argv - array of args
# [IN] switch - switch to seek
# [IN] val - expecting value
# [IN] alt - switch alternative
# returns value or True if val not expected
def parse_cmd(argv,switch,val=None,alt=None):
    for idx, x in enumerate(argv):
        if x == switch or x == alt:
            if val:
                if len(argv) > (idx+1):            
                    if not argv[idx+1].startswith('-'):
                        return argv[idx+1]
            else:
                return True

//expecting a value for -i
i = parse_cmd(sys.argv[1:],"-i", True, "--input")

//no value needed for -p
p = parse_cmd(sys.argv[1:],"-p")

Некоторые из наших клиентов в области биотехнологий недавно задали эти два вопроса:

  • Как мы можем выполнить скрипт Python как команду?
  • Как мы можем передать входные значения скрипту Python, когда он выполняется как команда?

Ниже я включил скрипт Python, который, как мне кажется, отвечает на оба этих вопроса. Предположим, что в файле test.py сохранен следующий скрипт Python:

      #
#----------------------------------------------------------------------
#
# file name: test.py
#
# input values: data  - location of data to be processed
#               date  - date data were delivered for processing
#               study - name of the study where data originated
#               logs  - location where log files should be written 
#
# macOS usage: 
#
#   python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
#
# Windows usage: 
#
#   python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
#
#----------------------------------------------------------------------
#
# import needed modules...
#
import sys
import datetime

def main(argv):

   #
   # print message that process is starting...
   #
   print("test process starting at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

   #
   # set local values from input values...
   #
   data = sys.argv[1]
   date = sys.argv[2]
   study = sys.argv[3]
   logs = sys.argv[4]

   #
   # print input arguments...
   #
   print("data value is", data)
   print("date value is", date)
   print("study value is", study)
   print("logs value is", logs)

   #
   # print message that process is ending...
   #
   print("test process ending at", datetime.datetime.now().strftime("%Y%m%d %H:%M"))

#
# call main() to begin processing...
#

if __name__ == '__main__':

   main(sys.argv)

Сценарий можно запустить на компьютере с macOS в оболочке терминала, как показано ниже, и результаты будут напечатаны в стандартный вывод (убедитесь, что текущий каталог содержит файл test.py):

      $ python3 test.py "/Users/lawrence/data" "20220518" "XYZ123" "/Users/lawrence/logs"
test process starting at 20220518 16:51
data value is /Users/lawrence/data
date value is 20220518
study value is XYZ123
logs value is /Users/lawrence/logs
test process ending at 20220518 16:51

Сценарий также можно выполнить на компьютере с Windows в командной строке, как показано ниже, и результаты будут напечатаны в стандартный вывод (убедитесь, что текущий каталог содержит файл test.py):

      D:\scripts>python test.py "D:\data" "20220518" "XYZ123" "D:\logs"
test process starting at 20220518 17:20
data value is D:\data
date value is 20220518
study value is XYZ123
logs value is D:\logs
test process ending at 20220518 17:20

Этот сценарий отвечает на оба поставленных выше вопроса и является хорошей отправной точкой для разработки сценариев, которые будут выполняться как команды с входными значениями.

Мое решение - 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
Другие вопросы по тегам