7 уровней построения интерфейсов командной строки на Python
Выполняйте свои скрипты Python, как команды bash
Написание скриптов Python для создания интерфейсов командной строки (CLI) — широко используемый метод для DevOps и бэкенд разработки.
Ключом к реализации CLI в Python является встроенный модуль argparse
. Он предоставляет все необходимые функции и позволяет использовать скрипт Python в качестве команды bash
.
В этой статье будут представлены некоторые важные моменты создания CLI с помощью Python на 7 уровнях сложности.
1. Запускаем базовый интерфейс командной строки с модулем argparse
Прежде всего, давайте создадим файл с именем test.py
и сделаем простой парсер аргументов:
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
После того, как мы определили этот парсер, теперь мы можем получать аргументы из командной строки. Каждый экземпляр ArgumentParser
содержит параметр --help
(или -h
качестве ярлыка) для вывода полезной информации.
$ python test.py --help
usage: test.py [-h]
optional arguments: -h, --help show this help message and exit
Однако из-за того, что мы не определили другие аргументы, следующий ввод вызовет ошибку:
$ python test.py 9
usage: test.py [-h]
test.py: error: unrecognized arguments: 9
2. Определяем позиционные аргументы
В командах bash
есть два типа аргументов. Один позиционный, другой необязательный.
Например, команда cp
имеет два позиционных аргумента:
$ cp source_file dest_file
source_file
указывает источники копируемого файла. И аргумент dest_file
указывает место для копирования файла.
Мы также можем определить позиционный аргумент для нашего интерфейса командной строки Python:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("num", type=int)
args = parser.parse_args()
print(args.num**2)
Как видно из приведенного выше кода, мы определили имя аргумента как num
и указали его тип как int
.
Теперь, если ввод из терминала является допустимым целым числом, наш скрипт Python будет печатать его квадрат:
$ python test.py 9
81
3. Добавляем больше полезной информации и описание
Как и многие команды Linux, хороший интерфейс командной строки должен предоставлять пользователям достаточно информации с помощью опции --help
.
С этой целью мы можем указать специальную информацию для соответствующих функций модуля argparse
.
import argparse
parser = argparse.ArgumentParser(prog='get_square',description='A CLI to calculate the square of an integer.')
parser.add_argument("num", type=int, help='An integer that needs to get the square value.')
args = parser.parse_args()
print(args.num**2)
Как показано выше, мы добавили информацию о программе и описании в экземпляр ArgumentParser
, чтобы дать ему имя и подробное описание. Кроме того, мы дали функции add_argument()
справочное сообщение, чтобы наши пользователи знали, для чего нужен этот аргумент.
Теперь давайте снова посмотрим на вывод опции -h
:
$ python test.py -h
usage: get_square [-h] num
A CLI to calculate the square of an integer.
positional arguments:
num An integer that needs to get the square value.
optional arguments:
-h, --help show this help message and exit
Это удобнее и информативнее, не правда ли? :)
4. Определяем необязательные аргументы
Помимо позиционных аргументов, для многих интерфейсов командной строки также необходимы необязательные аргументы.
Встроенная опция --help
всех экземпляров ArgumentParser
является необязательным аргументом. Мы можем добавить еще одну к предыдущему примеру:
import argparse
parser = argparse.ArgumentParser(prog='get_square',description='A CLI to calculate the square of an integer.')
parser.add_argument("num", type=int, help='An integer that needs to get the square value.')
parser.add_argument('--verbose',help='Print more info.')
args = parser.parse_args()
if args.verbose:
print(f'The square of {args.num} is {args.num**2}')
else:
print(args.num**2)
Вышеприведенная программа добавила необязательный аргумент с именем:
--verbose
. Если для этого аргумента есть значение, программа распечатает более подробную информацию для расчета.
Теперь давайте попробуем его использовать:
$ python test.py 9 --verbose 1
The square of 9 is 81
$ python test.py 9 --verbose 90908
The square of 9 is 81
$ python test.py 9 --verbose
usage: get_square [-h] [--verbose VERBOSE] num
get_square: error: argument --verbose: expected one argument
Досадная проблема заключается в том, что мы должны указать значение для этой опции, чтобы она работала, независимо от того, какое это значение. Если значения вообще нет, как показано выше, появится сообщение об ошибке.
Это связано с тем, что args.verbose
имеет значение None
, если мы используем его напрямую, не присваивая ему никаких значений.
Это не так удобно, как другие команды Linux. Поэтому нам нужно оптимизировать его через параметры action
.
5. Определяем специальные действия для необязательных аргументов
Давайте немного изменим эту строку кода:
parser.add_argument('--verbose',help='Print more info.', action='store_true')
Параметр action
функции add_argument()
может указать, как обрабатывать значения этой опции.
В нашем случае store_true
означает, что если указан параметр, программа по умолчанию присвоит значение True
для args.verbose
.
А затем выполните скрипт с опцией --verbose
напрямую:
$ python test.py 9 --verbose
The square of 9 is 81
Помимо store_true
или store_false
, Python также предоставляет другие варианты параметров action
. Давайте попробуем несколько:
Используйте "store_const" action
Мы можем использовать параметр store_const
в качестве действия и присвоить const
необязательному аргументу:
parser.add_argument('--verbose',help='Print more info.', action='store_const', const=1)
Поэтому значение args.verbose
всегда будет равным 1.
Параметр count
подсчитывает, сколько раз встречается необязательный аргумент. Давайте отредактируем наш код и попробуем:
import argparse
parser = argparse.ArgumentParser(prog='get_square',description='A CLI to calculate the square of an integer.')
parser.add_argument("num", type=int, help='An integer that needs to get the square value.')
parser.add_argument('--verbose',help='Print more info.', action='count')
args = parser.parse_args()
if args.verbose==2:
print(f'The square of {args.num} is {args.num**2}')
elif args.verbose==1:
print(f"{args.num}^2 == {args.num**2}")
else:
print(args.num**2)
За это время мы можем определить, насколько подробным будет вывод, по количеству опций --verbose
:
$ python test.py 9 --verbose --verbose
The square of 9 is 81
$ python test.py 9 --verbose 9^2 == 81
$ python test.py 9
81
Используйте "append" action
Действие append
сохраняет список и добавляет в список каждое значение аргумента. В некоторых случаях будет полезно хранить несколько значений необязательного аргумента.
Чтобы использовать его, измените следующую строку предыдущего кода Python:
parser.add_argument('--verbose',help='Print more info.', action='append')
Теперь мы можем добавить несколько значений аргумента --verbose
:
$ python test.py 9 --verbose 2 --verbose 3 --verbose 5
The verbose values are ['2', '3', '5']. The square of 9 is 81
6. Определяем ярлыки необязательных аргументов
Немного скучно много раз вводить --verbose
. Как ярлык -h
для опции --help
. Мы также можем определить ярлык для нашей опции --verbose
следующим образом:
parser.add_argument('-v','--verbose',help='Print more info.', action='count')
После определения ярлыка -v
мы можем использовать его напрямую:
$ python test.py 9 -vv
The square of 9 is 81
$ python test.py 9 -v
9^2 == 81
7. Работа с файлами в командной строке
Модуль argparse
также может обрабатывать аргументы файлового типа, что делает удобным выполнение некоторых основных файловых операций через интерфейсы командной строки.
Чтение файла через командную строку
Если мы хотим отображать содержимое файла построчно на терминале, мы можем написать скрипт Python следующим образом:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('f', type=argparse.FileType('r'))
args = parser.parse_args()
for line in args.f:
print(line.strip())
Теперь давайте выполним этот скрипт Python на терминале и передадим test.txt
в качестве аргумента файлового типа:
$ python test.py test.txt
Yang is writing a post. Yang is writing on Medium.
Как показано выше, файл test.txt
состоит из двух строк предложений. Они были правильно напечатаны на терминале с помощью нашего скрипта Python.
Запись данных в файл через командную строку
Чтобы записать данные в файл, нам нужно изменить оператор с r
на w
:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('f', type=argparse.FileType('w'))
args = parser.parse_args()
f = args.f
f.write('Yang is writing')
f.close()
Приведенный выше код запишет предложение «Ян пишет» в файл, назначенный через интерфейс командной строки. Использование его заключается в следующем:
$ python test.py test.txt
После выполнения вышеуказанной команды файл «test.txt» будет содержать одну строку предложения «Ян пишет».
Заключение
Освоение модуля argparse
в Python поможет нам разрабатывать и реализовывать простые в использовании интерфейсы командной строки с помощью сценариев Python.
В тех случаях, когда нам нужен настраиваемый интерфейс командной строки, но мы не утруждаем себя написанием сложных сценариев bash, этот модуль Python — наш лучший друг. ?