Обзор
Поскольку Python является таким популярным языком программирования, а также поддерживает большинство операционных систем, он стал широко использоваться для создания инструментов командной строки для многих целей. Эти инструменты могут варьироваться от простых приложений с интерфейсом командной строки до более сложных, таких как инструмент AWS awscli.
Сложные инструменты, подобные этому, обычно управляются пользователем с помощью аргументов командной строки , что позволяет пользователю использовать определенные команды, устанавливать параметры и многое другое. Например, эти параметры могут указывать инструменту на вывод дополнительной информации, чтение данных из указанного источника или отправку вывода в определенное место.
Обычно аргументы передаются инструментам CLI по-разному, в зависимости от вашей операционной системы:
- Подобно Unix:
-
за которым следует буква, например-h
, или--
за которым следует слово, например--help
- Windows:
/
за которым следует буква или слово, например/help
Эти разные подходы существуют по историческим причинам. Многие программы в Unix-подобных системах поддерживают как одинарное, так и двойное тире. Обозначение одинарного тире в основном используется с однобуквенными параметрами, а двойное тире представляет собой более читаемый список параметров, что особенно полезно для сложных параметров, которые должны быть более явными.
Примечание . В этой статье мы сосредоточимся исключительно на
Unix-подобном формате -
и --
.
Имейте в виду, что и имя, и значение аргумента специфичны для программы
- нет общего определения, кроме нескольких общих соглашений, таких как
--help
для получения дополнительной информации об использовании инструмента. Как разработчик сценария Python вы решаете, какие аргументы предоставить вызывающей стороне и что они будут делать. Это требует правильной оценки.
По мере роста вашего списка доступных аргументов ваш код станет более
сложным в попытках их точного анализа. К счастью, в Python есть ряд
библиотек, которые помогут вам в этом. Мы рассмотрим несколько наиболее
распространенных решений, от «сделай сам» с sys.argv
до подхода «
argparse
» с argparse.
Обработка аргументов командной строки с помощью Python
Python 3 поддерживает несколько различных способов обработки аргументов
командной строки. Встроенный способ - использовать модуль sys
С точки
зрения имен и использования, он имеет прямое отношение к библиотеке C (
libc
). Второй способ - это getopt
, который обрабатывает как
короткие, так и длинные параметры, включая оценку значений параметров.
Кроме того, существуют два других общих метода. Это модуль
argparse ,
который является производным от optparse
доступного до Python 2.7.
Другой метод - использование модуля docopt
, доступного на
GitHub .
У каждого из этих способов есть свои плюсы и минусы, поэтому стоит оценить каждый, чтобы увидеть, какой из них лучше всего соответствует вашим потребностям.
Модуль sys
Это базовый модуль, который с самого начала поставлялся с Python. Он
использует подход, очень похожий на библиотеку C, с использованием
argc
/ argv
для доступа к аргументам. Модуль
sys реализует аргументы
командной строки в простой структуре списка с именем sys.argv
.
Каждый элемент списка представляет собой единственный аргумент. Первый
элемент в списке sys.argv[0]
- это имя скрипта Python. Остальные
элементы списка, от sys.argv[1]
до sys.argv[n]
, являются
аргументами командной строки с 2 по n. В качестве разделителя между
аргументами используется пробел. Значения аргументов, содержащие пробел,
должны быть заключены в кавычки, чтобы их правильно проанализировал
sys
.
Эквивалент argc
- это просто количество элементов в списке. Чтобы
получить это значение, используйте оператор len()
Позже мы покажем это
на примере кода.
Печать первого аргумента CLI
В этом первом примере наш сценарий определит способ его вызова. Эта информация хранится в первом аргументе командной строки, индексированном нулем. В приведенном ниже коде показано, как получить имя сценария 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
# Count the arguments
arguments = len(sys.argv) - 1
print ("The script is called with %i arguments" % (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
# Count the arguments
arguments = len(sys.argv) - 1
# Output argument-wise
position = 1
while (arguments >= position):
print ("Parameter %i: %s" % (position, sys.argv[position]))
position = position + 1
Ниже мы вызываем наш код, который был сохранен в файле arguments-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
Помните, что смысл показа строки в кавычках заключается в том, что параметры обычно разделяются пробелом, если только они не заключены в кавычки.
Модуль getopt
Как вы могли заметить ранее, sys
разбивает строку командной строки
только на отдельные фасеты. Модуль Python
getopt идет немного
дальше и расширяет разделение входной строки проверкой параметров.
Основанный на getopt
, он позволяет использовать как короткие, так и
длинные варианты, включая присвоение значений.
На практике для правильной обработки входных данных sys
Для этого
необходимо заранее загрузить как модуль sys
getopt
Затем из списка
входных параметров мы удаляем первый элемент списка (см. Код ниже) и
сохраняем оставшийся список аргументов командной строки в переменной с
именем argument_list
.
# Include standard modules
import getopt, sys
# Get full command-line arguments
full_cmd_arguments = sys.argv
# Keep all but the first
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
short ставится двоеточие :
Это
сообщает getopt
что этой опции следует присвоить значение.
Теперь это позволяет нам обрабатывать список аргументов. Для getopt()
необходимо настроить три параметра - список фактических аргументов из
argv
, а также допустимые короткие и длинные параметры (показаны в
предыдущем фрагменте кода).
Сам вызов метода хранится в инструкции try-catch, чтобы скрыть ошибки во время оценки. Исключение возникает, если обнаруживается аргумент, который не является частью списка, как определено ранее. Скрипт Python выведет сообщение об ошибке на экран и выйдет с кодом ошибки 2.
try:
arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
# Output error, and return with an error code
print (str(err))
sys.exit(2)
Наконец, аргументы с соответствующими значениями сохраняются в двух
переменных с именами arguments
и values
. Теперь вы можете легко
оценить эти переменные в своем коде. Мы можем использовать for
для
перебора списка распознанных аргументов, одна запись за другой.
# Evaluate given options
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
в
качестве опции, что недопустимо.
Модуль argparse
Модуль argparse
доступен начиная с Python 3.2 и является расширением optparse
,
существующим до Python 2.7. Документация Python содержит описание API и
руководство, в котором подробно рассматриваются все методы.
Модуль предлагает интерфейс командной строки со стандартизованным
выводом, тогда как первые два решения оставляют большую часть работы в
ваших руках. argparse
позволяет проверять фиксированные и
необязательные аргументы с проверкой имени как в коротком, так и в
длинном стиле. В качестве необязательного аргумента по умолчанию он
включает -h
вместе с его длинной версией --help
. Этот аргумент
сопровождается справочным сообщением по умолчанию, описывающим принятые
аргументы.
В приведенном ниже коде показана инициализация парсера, а в выходных данных ниже показан основной вызов, за которым следует справочное сообщение. В отличие от вызовов Python, которые мы использовали в предыдущих примерах, не забывайте использовать Python 3 с этими примерами.
# Include standard modules
import argparse
# Initiate the parser
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
классу
argparse в качестве параметра description
Вызов этого кода ниже, вы
можете увидеть, как выглядит результат.
# Include standard modules
import argparse
# Define the program description
text = 'This is a test program. It demonstrates how to use the argparse module with a program description.'
# Initiate the parser with a 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
или
args.version
, и выводите сообщение о версии.
# Include standard modules
import argparse
# Initiate the parser
parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="show program version", action="store_true")
# Read arguments from the command line
args = parser.parse_args()
# Check for --version or -V
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"
. В других случаях вам
может потребоваться дополнительное присвоенное значение, например, если
вы укажете определенный объем, высоту или ширину. Это показано в
следующем примере. Обратите внимание, что по умолчанию все аргументы
интерпретируются как строки.
# Include standard modules
import argparse
# Initiate the parser
parser = argparse.ArgumentParser()
# Add long and short argument
parser.add_argument("--width", "-w", help="set output width")
# Read arguments from the command line
args = parser.parse_args()
# Check for --width
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
Заключение
В этой статье мы показали множество различных методов для получения
аргументов командной строки в Python, включая использование sys
,
getopt
и argparse
. Эти модули различаются по функциональности,
некоторые из них предоставляют гораздо больше, чем другие. sys
полностью гибок, тогда как для getopt
и argparse
требуется некоторая
структура. Напротив, они покрывают большую часть сложной работы, которую
система оставляет на ваше sys
Проработав предоставленные примеры, вы
сможете определить, какой модуль лучше всего подходит для вашего
проекта.
В этой статье мы не говорили о других решениях, таких как docopts
, мы
просто упомянули о нем. В этом модуле используется совершенно другой
подход, и он будет подробно описан в одной из следующих статей.