Обзор
Поскольку Python является очень популярным языком программирования, а также поддерживает большинство операционных систем и множество библиотек, упрощающих обработку аргументов командной строки, он стал широко использоваться для создания инструментов командной строки для многих целей. Эти инструменты могут варьироваться от простых приложений CLI до более сложных, таких как AWS. авскли инструмент.
Подобные сложные инструменты обычно контролируются пользователем через аргументы командной строки, который позволяет пользователю использовать определенные команды, устанавливать параметры и многое другое. Например, эти параметры могут указывать инструменту выводить дополнительную информацию, читать данные из указанного источника или отправлять выходные данные в определенное место.
В общем, аргументы передаются инструментам CLI по-разному, в зависимости от вашей операционной системы:
- Unix-подобный:
-
за которым следует буква, например-h
или--
за которым следует слово, например--help
- Windows:
/
за которым следует буква или слово, например/help
Эти разные подходы существуют по историческим причинам. Многие программы в Unix-подобных системах поддерживают как одинарное, так и двойное тире. Обозначение одинарного тире в основном используется с параметрами, состоящими из одной буквы, тогда как двойное тире представляет собой более удобочитаемый список параметров, что особенно полезно для сложных параметров, которые должны быть более явными.
Внимание: В этой статье мы сосредоточимся исключительно на Unix-подобном формате -
и --
.
Имейте в виду, что и имя, и значение аргумента специфичны для программы — общего определения не существует, кроме нескольких общих соглашений, таких как --help
для получения дополнительной информации об использовании инструмента. Как разработчик скрипта Python, вы решаете, какие аргументы предоставить вызывающей стороне и что они будут делать. Это требует правильной оценки.
По мере роста списка доступных аргументов ваш код будет становиться все более сложным в попытке точного их анализа. К счастью, в Python есть ряд библиотек, которые помогут вам в этом. Мы рассмотрим несколько наиболее распространенных решений: от «сделай сам» до sys.argv
, к подходу «сделано для вас» с argparse
.
Обработка аргументов командной строки с помощью Python
Python 3+ и экосистема вокруг него поддерживают множество различных способов обработки аргументов командной строки. Есть многих библиотеки, упрощающие анализ аргументов командной строки.
Встроенный способ заключается в использовании sys
модуль. С точки зрения имен и использования они напрямую связаны с библиотекой C (libc
).
Второй способ – это getopt
модуль, который обрабатывает как короткие, так и длинные параметры, включая оценку значений параметров.
Ассоциация модуль argparse, который получен из optparse
модуль (доступен до Python 2.7).
Ассоциация docopt
модуль, который доступно на GitHub, также обеспечивает ту же функциональность.
В последнее время absl
библиотека также набирает обороты как средство замены optparse
и getopt()
.
У каждого из этих способов есть свои плюсы и минусы, поэтому стоит оценить каждый из них, чтобы понять, какой из них лучше всего соответствует вашим потребностям.
Системный модуль
Это базовый модуль, поставляемый вместе с Python с самого начала. Подход очень похож на библиотеку C, используя argc
/argv
чтобы получить доступ к аргументам. системный модуль реализует аргументы командной строки в простой структуре списка с именем sys.argv
.
Каждый элемент списка представляет один аргумент. Первый элемент в списке,
sys.argv[0]
, — это имя скрипта Python. Остальные элементы списка,sys.argv[1]
вsys.argv[n]
, — это аргументы командной строки со 2 по n.
В качестве разделителя между аргументами используется пробел. Значения аргументов, содержащие пробел, должны быть заключены в кавычки, чтобы их можно было правильно проанализировать. sys
.
Эквивалент argc
это просто количество элементов в списке. Чтобы получить это значение, используйте Python len()
оператор. Позже мы покажем это на примере кода.
Печать первого аргумента CLI
В этом первом примере наш скрипт определит способ его вызова. Эта информация хранится в первом аргументе командной строки с индексом 0. Код ниже показывает, как получить имя вашего скрипта Python:
import sys
print("The script has the name %s" % (sys.argv[0])
Сохраните этот код в файле с именем arguments-program-name.py
, а затем вызовите его, как показано ниже. Вывод выглядит следующим образом и содержит имя файла, включая его полный путь:
$ python arguments-program-name.py
The script has the name arguments-program-name.py
$ python /home/user/arguments-program-name.py
The script has the name /home/user/arguments-program-name.py
Как видно из второго вызова выше, мы получаем не только имя файла Python, но и полный путь, используемый для его вызова.
Подсчет количества аргументов
Во втором примере мы просто подсчитываем количество аргументов командной строки, используя встроенную функцию len()
метод. sys.argv
это список, который мы должны изучить. В приведенном ниже коде мы получаем количество аргументов, а затем вычитаем 1, поскольку один из этих аргументов (т. е. первый) всегда устанавливается как имя файла, что не всегда нам полезно. Таким образом, фактическое количество аргументов, переданных пользователем, равно len(sys.argv) - 1
:
import sys
arguments = len(sys.argv) - 1
print ("The script is called with %i arguments" % (arguments))
Сохраните этот файл и назовите его аргументы-count.py. Некоторые примеры вызова этого сценария показаны ниже. Сюда входят три различных сценария:
- Вызов без дополнительных аргументов командной строки
- Вызов с двумя аргументами
- Вызов с двумя аргументами, где второй — строка в кавычках, содержащая пробел.
$ python arguments-count.py
The script is called with 0 arguments
$ python arguments-count.py --help me
The script is called with 2 arguments
$ python arguments-count.py --option "long string"
The script is called with 2 arguments
Перебор аргументов
В нашем третьем примере выводятся все аргументы, отправленные в скрипт Python, за исключением самого имени программы. Поэтому мы просматриваем аргументы командной строки, начиная с второй элемент списка. Напомним, что это индекс 1, поскольку в Python списки отсчитываются от 0:
import sys
arguments = len(sys.argv) - 1
position = 1
while (arguments >= position):
print ("Parameter %i: %s" % (position, sys.argv[position]))
position = position + 1
Ниже мы вызываем наш код, который был сохранен в файле аргументы-output.py. Как и в предыдущем примере, выходные данные иллюстрируют три разных вызова:
- Звонок без аргументов
- Вызов с двумя аргументами
- Вызов с двумя аргументами, где второй аргумент представляет собой строку в кавычках, содержащую пробел.
$ python arguments-output.py
$ python arguments-output.py --help me
Parameter 1: --help
Parameter 2: me
$ python arguments-output.py --option "long string"
Parameter 1: --option
Parameter 2: long string
Помните, что смысл примера строки в кавычках заключается в том, что параметры обычно разделяются пробелом. если не они заключены в кавычки.
Флаги спуска (absl
)
Библиотека флагов Abseil предназначена для переноса аргументов командной строки в производство с помощью распределенных аргументов командной строки. Когда модуль использует флаги командной строки и импортируется в другой модуль – другой модуль также импортирует флагии может обрабатывать их, пересылая в импортированный модуль.
Это делает сложные аргументы командной строки, разделяемые между модулями, более простыми и менее многословными.
Кроме того, библиотека позволяет вам определять значения по умолчанию, описания и типы данных аргументов, поэтому дополнительные проверки и преобразования не требуются.
from absl import flags
import sys
flags.DEFINE_string('name', 'User', 'The name of the user.')
FLAGS = flags.FLAGS
FLAGS(sys.argv)
print(f"Hello {FLAGS.name}!")
Поддерживаемые типы данных:
DEFINE_integer()
DEFINE_string()
DEFINE_bool()
DEFINE_enum()
DEFINE_list()
DEFINE_float()
А также DEFINE_multi_integer()
, DEFINE_multi_string()
и DEFINE_multi_enum()
для ввода нескольких аргументов. Кроме того, бег --help
, --helpfull
и т. д. распечатайте существующие флаги и их описания в разных форматах.
Ознакомьтесь с нашим практическим руководством по изучению Git с рекомендациями, принятыми в отрасли стандартами и прилагаемой памяткой. Перестаньте гуглить команды Git и на самом деле изучить это!
Библиотека также позволяет определять проверки — как с точки зрения диапазона, например, целочисленные значения, имеющие upper_bound
or lower_bound
это приемлемо, и запуск произвольных методов для проверки значений:
def validate_name(value):
return len(value) > 15
flags.register_validator('name',
validate_name,
message='Name is over 15 characters long.',
flag_values=FLAGS)
Собираем их в конкретный пример:
from absl import flags
import sys
flags.DEFINE_string('name', 'User', 'The name of the user.')
flags.DEFINE_integer('tasks', 0, 'The number of tasks a user has.', lower_bound=0)
FLAGS = flags.FLAGS
FLAGS(sys.argv)
print(f"{FLAGS.name} has {FLAGS.tasks} tasks to work on.")
$ python flags.py --name=John --tasks=5
John has 5 tasks to work on.
$ python flags.py --name=John --tasks=-1
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_flag.py", line 180, in _parse
return self.parser.parse(argument)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_argument_parser.py", line 168, in parse
raise ValueError('%s is not %s' % (val, self.syntactic_help))
ValueError: -1 is not a non-negative integer
...
Модуль argparse
Ассоциация модуль argparse доступен начиная с Python 3.2, а также является усовершенствованием optparse
модуль, существующий до Python 2.7. Документация Python содержит описание API и руководство, в котором подробно описаны все методы.
Модуль предлагает интерфейс командной строки со стандартизированным выводом, тогда как первые два решения оставляют большую часть работы в ваших руках. argparse
позволяет проверять фиксированные и необязательные аргументы с проверкой имени как в коротком, так и в длинном стиле. В качестве необязательного аргумента по умолчанию он включает -h
, вместе с его длинной версией --help
. Этот аргумент сопровождается справочным сообщением по умолчанию, описывающим принятые аргументы.
Код ниже показывает инициализацию синтаксического анализатора, а выходные данные ниже, показывающие базовый вызов, за которым следует справочное сообщение. В отличие от вызовов Python, которые мы использовали в предыдущих примерах, не забывайте использовать Python 3 в этих примерах:
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
$ python3 arguments-argparse-basic.py
$ python3 arguments-argparse-basic.py -h
usage: arguments-argparse-basic.py [-h]
optional arguments:
-h, --help show this help message and exit
$ python3 arguments-argparse-basic.py --verbose
usage: arguments-argparse-basic.py [-h]
arguments-argparse-basic.py: error: unrecognized arguments: --verbose
На следующем этапе мы добавим собственное описание в справочное сообщение для наших пользователей. Инициализация парсера таким образом позволяет добавить дополнительный текст. В приведенном ниже коде описание сохраняется в text
переменная, которая явно задана argparse
класс как description
параметр. Вызвав этот код ниже, вы можете увидеть, как выглядит результат:
import argparse
text = 'This is a test program. It demonstrates how to use the argparse module with a program description.'
parser = argparse.ArgumentParser(description=text)
parser.parse_args()
$ python3 arguments-argparse-description.py --help
usage: arguments-argparse-description.py [-h]
This is a test program. It demonstrates how to use the argparse module with a
program description.
optional arguments:
-h, --help show this help message and exit
На последнем шаге мы добавим необязательный аргумент с именем -V
, который имеет соответствующий аргумент длинного стиля с именем --version
. Для этого мы используем метод add_argument()
который мы вызываем с тремя параметрами (отображаемыми для --version
, только):
- Имя параметра:
--version
- Текст справки для параметра:
help="show program version"
- Действие (без дополнительной стоимости):
action="store_true"
Исходный код для этого показан ниже. Чтение аргументов в переменную с именем args
делается через parse_args()
метод из parser
объект. Обратите внимание, что вы отправляете как короткую, так и полную версию за один вызов. Наконец, вы проверяете, являются ли атрибуты args.V
or args.version
установлены и выводят сообщение о версии:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="show program version", action="store_true")
args = parser.parse_args()
if args.version:
print("This is myprogram version 0.1")
$ python3 arguments-argparse-optional.py -V
This is myprogram version 0.1
$ python3 arguments-argparse-optional.py --version
This is myprogram version 0.1
Ассоциация --version
Аргумент не требует указания значения в командной строке. Вот почему мы установили аргумент действия "store_true"
. В других случаях вам может потребоваться дополнительное присвоенное значение, например, если вы указываете определенный объем, высоту или ширину. Это показано в следующем примере. Обратите внимание, что по умолчанию все аргументы интерпретируются как строки:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--width", "-w", help="set output width")
args = parser.parse_args()
if args.width:
print("Set output width to %s" % args.width)
Здесь мы покажем, что происходит при отправке разных значений аргументов. Сюда входит как короткая, так и длинная версия, а также справочное сообщение:
$ python3 arguments-argparse-optional2.py -w 10
Set output width to 10
$ python3 arguments-argparse-optional2.py --width 10
Set output width to 10
$ python3 arguments-argparse-optional2.py -h
usage: arguments-argparse-optional2.py [-h] [--width WIDTH]
optional arguments:
-h, --help show this help message and exit
--width WIDTH, -w WIDTH
set output width
Модуль getopt
Как вы, возможно, уже заметили, sys
Модуль разбивает строку командной строки только на отдельные фасеты. Питон модуль getopt идет немного дальше и расширяет разделение входной строки путем проверки параметров. На основе getopt
C, она допускает как короткие, так и длинные варианты, включая присвоение значения.
На практике это требует sys
модуль для правильной обработки входных данных. Для этого оба sys
модуль и getopt
модуль необходимо загрузить заранее. Далее из списка входных параметров мы удаляем первый элемент списка (см. код ниже) и сохраняем оставшийся список аргументов командной строки в переменной с именем argument_list
:
import getopt, sys
full_cmd_arguments = sys.argv
argument_list = full_cmd_arguments[1:]
print argument_list
Аргументы в argument_list
теперь можно проанализировать с помощью getopts()
метод. Но прежде чем это сделать, нам нужно рассказать getopts()
о том, какие параметры действительны. Они определяются следующим образом:
short_options = "ho:v"
long_options = ["help", "output=", "verbose"]
Это означает, что эти аргументы мы считаем действительными, а также некоторую дополнительную информацию:
------------------------------------------
long argument short argument with value
------------------------------------------
--help -h no
--output -o yes
--verbose -v no
------------------------------------------
Вы могли заметить, что o
короткий вариант начинался через двоеточие, :
, Это говорит getopt
что этой опции должно быть присвоено значение.
Теперь это позволяет нам обрабатывать список аргументов. getopt()
метод требует настройки трёх параметров — списка фактических аргументов из argv
, а также допустимые короткие и длинные параметры (показаны в предыдущем фрагменте кода).
Сам вызов метода сохраняется в операторе try-catch, чтобы исключить ошибки во время оценки. Исключение возникает, если обнаружен аргумент, который не является частью списка, определенного ранее. Сценарий Python выведет сообщение об ошибке на экран и завершит работу с кодом ошибки 2:
try:
arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
print (str(err))
sys.exit(2)
Наконец, аргументы с соответствующими значениями сохраняются в двух переменных с именами arguments
и values
. Теперь вы можете легко оценить эти переменные в своем коде. Мы можем использовать for
-цикл для перебора списка распознанных аргументов, одна запись за другой.
for current_argument, current_value in arguments:
if current_argument in ("-v", "--verbose"):
print ("Enabling verbose mode")
elif current_argument in ("-h", "--help"):
print ("Displaying help")
elif current_argument in ("-o", "--output"):
print (("Enabling special output mode (%s)") % (current_value))
Ниже вы можете увидеть результат выполнения этого кода. Мы покажем, как программа реагирует как на действительные, так и на недопустимые аргументы программы:
$ python arguments-getopt.py -h
Displaying help
$ python arguments-getopt.py --help
Displaying help
$ python arguments-getopt.py --output=green --help -v
Enabling special output mode (green)
Displaying help
Enabling verbose mode
$ python arguments-getopt.py -verbose
option -e not recognized
Последний вызов нашей программы на первый взгляд может показаться немного запутанным. Чтобы понять это, вам нужно знать, что сокращенные параметры (иногда называемые также флагами) могут использоваться вместе с одним тире. Это позволяет вашему инструменту легче принимать множество опций. Например, вызов python arguments-getopt.py -vh
это то же самое, что позвонить python arguments-getopt.py -v -h
. Итак, в последнем вызове выше getopt
модуль думал, что пользователь пытается пройти -e
как вариант, который недействителен.
Заключение
В этой статье мы показали множество различных методов получения аргументов командной строки в Python, в том числе использование sys
, getopt
и argparse
. Эти модули различаются по функциональности, некоторые предоставляют гораздо больше, чем другие. sys
является полностью гибким, тогда как оба getopt
и argparse
требуют некоторой структуры. Напротив, они охватывают большую часть сложной работы, sys
оставляет на ваше усмотрение. Проработав предоставленные примеры, вы сможете определить, какой модуль лучше всего подходит для вашего проекта.
В этой статье мы не говорили о других решениях, таких как docopts
модуль, мы только что упомянули об этом. Этот модуль использует совершенно другой подход и будет подробно описан в одной из следующих статей.