Как читать / обрабатывать аргументы командной строки?
Я изначально программист на Си. Я видел множество трюков и "хаков", чтобы прочитать много разных аргументов.
Каким образом программисты Python могут это сделать?
связанные с
- Каков наилучший способ получить / проанализировать аргументы командной строки, передаваемые скрипту Python?
- Реализовываете интерфейсы командной строки в стиле "[команда] [действие] [параметр]"?
- Как я могу обработать аргументы командной строки в Python?
- Как мне отформатировать позиционный аргумент, используя optparse в Python?
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 кажется очевидным выбором, когда это так.
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)
Причина нового ответа:
- В существующих ответах указано несколько вариантов.
- Стандартным вариантом является использование , в нескольких ответах приведены примеры из документации, а в одном ответе указано его преимущество. Но все не могут адекватно / четко объяснить ответ на фактический вопрос ОП, по крайней мере, для новичков.
Пример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