![]() |
Обработка аргументов командной строки в Python |
![]() |
Задача разбора аргументов командной строки
При запуске любой программы существует возможность передавать ей параметры, называемые аргументами командной строки (далее - АКС). Несмотря на название, АКС можно передавать и графическим приложениям. Формат и содержание АКС могут быть произвольными и определяются кодом самой программы. Каждый язык программирования предлагает средства для получения и обработки АКС (чаще всего - в виде массива или списка строк).
Под задачей разбора АКС понимается процесс извлечения из АКС каких-либо значений и сохранение их в отдельных переменных программы. Это делается для того, чтобы в дальнейшем разработчику было удобнее получать доступ к значениям конкретных АКС.
Если программа имеет большое количество возможных АКС, задача их разбора усложняется. Написание обрабатывающего кода для каждого аргумента оказывается монотонной работой, в которой легко допустить ошибку. Для автоматизации разбора АКС многие ЯП предоставляют соответствующие библиотеки. Идея, заложенная в них, заключается в следующем:
- Разработчик с помощью функций или классов библиотеки описывает допустимые для своей программы АКС в декларативном стиле.
- Библиотека производит объект синтаксического анализатора (англ. parser), который будет производить синтаксический разбор АКС в соответствии с декларативным описанием.
- На вход объекту подаются фактические АКС.
- В результате своей работы парсер “раскладывает” значения АКС по соответствующим переменным.
К библиотекам разбора АКС относятся: getopt для C, boost::program_options для C++, CommandLineParser для C#, optparse-applicative для Haskell и argparse для Python, с которой мы познакомимся в этой работе.
Структура аргументов командной строки
В результате появления библиотек для разбора АКС, и несмотря на отсутствие стандартизации в этой области, сложились негласные правила форматирования АКС. Согласно этим правилам, АКС подразделяются на следующие группы:
- Флаги (англ. flags).
- Опции (англ. options).
- Позиционные аргументы (англ. positional arguments).
- Команды (англ. commands или subcommands).
Флаги и опции предваряются одним или несколькими специальными символами, которые
и отличают их от позиционных аргументов и команд. Наиболее распространённым
символов является '-'
, а в ОС Windows традиционно используется '/'
. Спецсимвол
пишется один раз перед однобуквенными флагами и опциями и дважды перед
многобуквенными. Опции отличаются от флагов тем, что они требуют значение в
качестве параметра, в то время как флаги параметров не имеют. Некоторые флаги и
опции могут одновременно иметь краткий однобуквенный и длинный многобуквенный
варианты. Рассмотрим применение флагов и опций на примере консольных приложений
Unix-подобных ОС:
# выводит список файлов в текущей директории в виде списка
ls -l
# выводит количество слов и строк в файле input.txt
wc -w -l input.txt
# находит все вхождения слова "what" во всех файлах внутри директории "where"
grep -r --color what where
# выводит первые 5 строк из файла input.txt
head -n 5 input.txt
АКС -l
, -w
, -r
и --color
в примере выше являются опциями, т.к. не
принимают никаких значений в качестве параметров; АКС -n
является опцией, т.к.
он принимает количество строк, которые необходимо вывести; АКС input.txt
,
what
и where
- позиционными аргументами, т.к. не начинаются со спецсимвола.
Некоторые библиотеки позволяют объединять несколько однобуквенных флагов или опций,
идущих подряд, в один АКС без потери смысла. Например, команду wc
из примера
выше можно записать так:
wc -wl input.txt
Параметры однобуквенных опций можно так же объединять с самой опцией:
head -n5 input.txt
Многобуквенные опции отделяются от параметра пробелом или символом =
:
# распаковывает архив archive.tar
tar -xv --file=archive.tar
Позиционные аргументы и команды не имеют в начале никаких специальных символов. Позиционными аргументами, чаще всего, являются имена файлов или адреса каких либо ресурсов:
# удаляет file1.txt и file2.txt
rm file1.txt file2.txt
# посылает эхо-запрос на сайт onlyfans.com
ping onlyfans.com
Позиционные аргументы называются так, потому что могут менять смысл в зависимости от своей позиции:
# копирует file1.txt в file2.txt
cp file1.txt file2.txt
# наоборот, копирует file2.txt в file1.txt
cp file2.txt file1.txt
Командами называются АКС, которые разрешают или запрещают использование других АКС, или же меняют их смысл:
# В ОС FreeBSD выводит аннотацию для установленного пакета
# "info" - команда, которая выводит информацию о заданном пакете
# "-A" - флаг, который при команде info выводит аннотацию
pkg info -A firefox
# Устанавливает пакет и помечает его как установленный автоматически
# "install" - команда для установки пакетов
# "-A" - флаг, который при команде install помечает его автоматически установленным
pkg install -A firefox
Библиотека argparse
В этом разделе изложим краткое руководство по использованию модуля argparse
.
Подробная информация о нём находится в официальной документации Python.
Перед началом использования библиотеки необходимо импортировать соответствующий модуль в свою программу:
import argparse
Парсер создаётся вызовом конструктора ArgumentParser()
, а его запуск производится
с помощью метода parse_args()
:
= argparse.ArgumentParser()
parser
parser.parse_args()
Несмотря на то, что мы ещё не объявили ни одного АКС, argparse
автоматически
создаёт флаг -h,--help
, который выводит справку по использованию программы.
Все остальные АКС должны объявляться разработчиком перед вызовом parse_args()
.
Перечислим некоторые именованные аргументы конструктора ArgumentParser()
:
prog
. Имя программы, которое будет отображаться в справке. Значение по умолчанию -sys.argv[0]
.description
. Текстовое описание, которое отображается в справке перед информацией о доступных АКС.epilog
. Текстовое описание, которое отображается в справке после информации о АКС.prefix_chars
. Множество символов, обозначающих начало флага или опции. Значение по умолчанию -'-'
.allow_abbrev
. Определяет, допустимо ли сокращать многобуквенные флаги и опции. Если включено, то вместо--longoption
можно писать, например,--longop
. Значение по умолчанию -True
.exit_on_error
. Определяет, должен ли вызовparse_args()
приводить к завершению программы, если один или несколько АКС не могут быть корректно разобраны.
Перепишем пример выше с использованием этих аргументов:
= argparse.ArgumentParser(prog="myprog", description="My awesome program",
parser ="All rights reserved", prefix_chars="-+",
epilog=False, exit_on_error=False)
allow_abbrev
parser.parse_args()
Добавление АКС осуществляется с помощью метода add_argument()
:
"filename") parser.add_argument(
В примере выше объявляется позиционный аргумент с именем filename
. Запустив
программу с флагом -h
можно увидеть, что этот аргумент появился в справке.
Рассмотрим подробно параметры метода:
- Первыми и неименованными параметрами должны быть имена создаваемого флага,
опции или позиционного аргумента. Библиотека отличает позиционные аргументы
от флагов и опций по наличию предваряющего спецсимвола. Например,
.add_argument("-a", "--aaaa", "--bbbb")
создаёт синонимичные флаги-a
,--aaaa
и--bbbb
. action
. Задаёт действие, которое должен совершить парсер, когда он обнаруживает данный АКС в строке. Значениями данного параметра могут быть следующие строки:'store'
. Сохраняет значение опции в соответствующую ей переменную. Является значением по умолчанию.'store_const'
. Сохраняет константу в переменную, соответствующую опции. Сама константа передаётся через другой параметр -const
.'store_false'
и'store_true'
. Специальные вариантыstore_const
, которые сохраняютFalse
иTrue
, соответственно.'append'
. Работает подобноstore
, но если опция указана несколько раз, то не перезаписывает хранимое значение, а составляет список из всех переданных значений.'append_const'
. Подобноappend
, дописывает в список указанную константу.'count'
. Подсчитывает сколько раз флаг перечислен в командной строке.'extend'
. Работает подобноappend
, но позволяет дописывать в список сразу несколько значений при переданном параметреnargs
.
nargs
. По умолчаниюargparse
производит одно действие для каждого отдельного обрабатываемого АКС. С помощью этого параметра можно изменить это поведение. Значениямиnargs
могут быть:- целое число. Группирует заданное количество значений опции или позиционного аргумента.
'?'
. Значение опции или позиционного аргумента берётся из командной строки, если оно там указано. Иначе - значение берётся из параметраdefault
, если опция указана без значения и из параметраconst
в остальных случаях.'*'
. Все значения собираются в список.'+'
. Все значения собираются в список, причём опция или позиционный аргумент должны быть указаны хотя бы один раз.
const
. Применяется для задания значения, которое будет ассоциированно с АКС, не имеющими соответствующих им значений в командной строке. Два наиболее распространённых случая, в которых применяетсяconst
:- Когда
add_argument()
вызван сaction='store_const'
илиaction='append_const'
этот параметр определяет какое именно значение будет установлено или добавлено в список значений АКС. - Когда
add_argument()
определяет опцию вида-f,--foo
и вызван сnargs='?'
. В этом случае значениеconst
используется, если опция в командной строке была указана без значения.
- Когда
default
. Для опций и позиционных аргументов указывает значение, которое должно быть использовано, если эта опция или аргумент не указаны в командной строке.type
. Задаёт функцию, которая будет вызвана над значением опции или позиционного аргумента. Чаще всего используется для конвертирования строковых значений в нужные пользователю. В качестве значения этого параметра может быть использована любая функция, принимающая один параметр-строку.choices
. Используется для создания опции или позиционного аргумента, которые должны принимать строго определённый набор значений.required
. Булевый параметр, определяющий, является ли АКС обязательным. Значение по умолчанию:False
.metavar
. Устанавливает текст, который будет выводиться в справке вместо параметров опций и позиционных аргументов.dest
. Задаёт имя поля, в которое будет сохранено значение АКС. Если не указано, то вычисляется из имени флага, опции или позиционного аргумента.
Рассмотрим подробный пример, использующий описанные выше параметры:
# опция -f с синонимом --foo
"-f", "--foo")
parser.add_argument(
# флаг -g, сохраняющий значение 42, если он был передан
"-g", action="store_const", const=42)
parser.add_argument(
# флаги --yes и --no, сохраняющие, если переданы, True и False, соответственно.
"--yes", action="store_true")
parser.add_argument("--no", action="store_false")
parser.add_argument(
# опция -h, который можно указывать несколько раз, значения которого будут собраны в список
"-h", action="append")
parser.add_argument(
# флаги --with-pasta и --with-pizza, которые, если указаны, собирают в список
# под именем order строковые константы "pasta" и "pizza", соответственно
"--with-pasta", action="append_const", dest="order", const="pasta")
parser.add_argument("--with-pizza", action="append_const", dest="order", const="pizza")
parser.add_argument(
# флаг -v, сохраняющий количество вхождений в командную строку
# например, "-v -v -v" будет сохранять 3
"-v", action="count", default=0)
parser.add_argument(
# опция --items, которую можно указывать несколько раз, и которая может иметь
# одно или более значений
# например, --items ball --items pen boots сохранит ["ball", "pen", "boots"]
"--items", action="extend", nargs="+")
parser.add_argument(
# опция --between, принимающая строго два параметра
"--between", nargs=2)
parser.add_argument(
# позиционный параметр infile, который если не указан, использует значение по
# умолчанию "input.txt"
"infile", nargs="?", default="input.txt")
parser.add_argument(
# позиционный параметр direction, который может принимать
# только значения "up", "down", "left" и "right"
"direction", choices=["up", "down", "left", "right"]) parser.add_argument(
В результате успешного завершения метода parse_args()
возвращается объект,
содержащий значения разобранных АКС в качестве своих полей. Имена полей
определяются параметром dest
при вызове add_argument()
:
= argparse.ArgumentParser()
parser
"filename")
parser.add_argument(
= parser.parse_args()
args
print(args.filename)
Формат CSV
Для выполнения данной работы необходимо также познакомиться с форматом CSV.
CSV (англ. Comma Separated Values, значения разделённые запятыми) - текстовый формат представления простых табличных данных. Для создания CSV-файла достаточно обычного текстового редактора, однако табличные процессоры вроде LibreOffice Calc и Microsoft Excel так же имеют возможность экспортировать данные в CSV. Пример содержимого простейшего CSV-файла приведён ниже:
ФИО,Стаж,Зарплата
Дегтярёв Данил Игоревич,2,7000
Попов Глеб Александрович,7,300000/сек
Несмотря на название, CSV-файлы иногда разделяются не символами ,
, а какими-либо
другими. Microsoft Excel разделяет ячейки с помощью ;
или символа табуляции,
а так же имеет некоторые другие особенности форматирования.
Для чтения, обработки и записи CSV-файлов в языке Python имеется библиотека csv
.
Ознакомимся с её программным интерфейсом.
Функция reader()
возвращает объект-читатель, который позволяет считывать
содержимое CSV-файла построчно. Идея этого объекта во многом напоминает идею,
стоящую за потоками ввода/вывода (StreamReader
и FileStream
в C#). В качестве
первого её параметра передаётся любой итерируемый объект, из которого будет
черпаться информация. Это означает, что объект-читатель CSV может читать данные
не только из файлов, но и, например, из переменных-списков. Именованные аргументы
функции reader()
включают:
delimiter
. Задаёт символ-разделитель в CSV-файле. По умолчанию -','
.quotechar
. Задаёт символ, которым обрамляются ячейки, содержащие спецсимволы. По умолчанию -'"'
.escapechar
. Задаёт символ, который используется для экранирования спецсимволов.doublequote
. Определяет как экранировать символquotechar
, если он встречается в самой ячейке. При значенииFalse
к этому символу приписывается символescapechar
, приTrue
- символ дублируется. По умолчанию -True
.skipinitialspace
. Определяет, игнорировать ли пробелы, следующие сразу за символом-разделителем. По умолчанию -False
.
Функция writer()
принимает тот же набор аргументов, что и reader()
, и
возвращает объект-писатель. Этот объект аналогичен StreamWriter
в C# и позволяет
построчно записывать данные в формате CSV.
Объект-читатель может производить чтение построчно путем организации цикла for
по этому объекту. Чтобы прочитать файл целиком, объект-читатель нужно сконвертировать
в список.
Объект-писатель имеет метод writerow()
, принимающий список ячеек и записывающий
очередную строку в CSV-файл, а так же метод writerows()
, принимающий список
списков ячеек.
Важно иметь ввиду, что при вызове reader()
или writer()
над файлами,
необходимо обязательно указывать параметр newline=''
при их открытии.
Приведём пример, демонстрирующий применение описанных функций:
import csv
= open("input.csv", newline='')
infile = csv.reader(infile, delimiter='\t', quotechar='|', skipinitialspace=True)
reader
for line in reader:
for cell in line:
print("Ячейка содержит " + cell)
= open("output.csv", "w", newline='')
outfile = csv.writer(outfile)
writer
= ["a", "b", "c"]
l1 = ["x", "y", "z"]
l2
writer.writerow(l1) writer.writerow(l2)
Более подробную информацию о модуле csv
можно найти в
официальной документации.
Контрольные вопросы
- Виды аргументов командной строки и их отличия.
- Что такое парсер АКС и какую задачу он решает?
- Что означают символы
{}
и[]
в справке по использованию программы? - Что такое экранирование символов?
Задание на лабораторную работу
- Написать программу на Python, обрабатывающую аргументы командной строки в соответствии с вариантом. Программа должна прочитывать матрицу из CSV-файла и производить над ней операции, в зависимости от указанных аргументов командной строки. Изменённая матрица должна выводиться в выходной CSV-файл, путь до которого так же указывается в аргументах командной строки. В программе должна присутствовать обработка ошибочного ввода.
- Запустить написанную программу и вывести справку по её использованию, а затем убедиться в ее правильном функционировании при введённых входных данных.
Варианты заданий
Вариант 1
- Аргумент
-i,--input
задаёт путь до входного CSV-файла. Обязательный аргумент. - Аргумент
-o,--output
задаёт путь до выходного CSV-файла. Если не указан - имя генерируется на основе входного файла. - Аргумент
-v
. Если он указан, то программа выводит на экран промежуточные значения во время своей работы. - Обязательный параметр, принимающий лишь значения “rows” и “cols”. В зависимости от значения этого параметра, программа меняет строки или столбцы матрицы между собой местами.
Вариант 2
- Обязательный параметр, задающий путь до входного CSV-файла.
- Обязательный параметр, задающий путь до выходного CSV-файла.
- Аргумент
-n
, задающий номер строки матрицы, в которую программа должна поместить суммы элементов всех остальных строк, включая эту. Значение по умолчанию -0
. - Аргумент
-q,--quiet
, необязательный. Если он указан, то программа подавляет любые сообщения об ошибках.
Вариант 3
- Обязательный параметр, задающий путь до входного CSV-файла.
- Выходной файл не указывается, программа всегда перезаписывает входной CSV-файл.
- Аргумент
-b,--backup
, определяющий, нужно ли создавать копию входного CSV-файла перед его перезаписью. - Аргумент
-r,--row
, задающий номер столбца, половину элементов которого программа должна занулить.
Вариант 4
- Аргумент
-i,--input
задаёт путь до входного CSV-файла. Обязательный аргумент. - Аргумент
-o,--output
задаёт путь до выходного CSV-файла. Если не указан - имя генерируется на основе входного файла. - Аргумент
-s
, задающий размер квадратной матрицы, до которой программа должна урезать исходную. Если исходная матрица имеет меньший размер, чем значение параметра-s
, то программа должна выводить ошибку. - Аргумент
-n
, необязательный. Если он указан, то программа не выполняет обрезание матрицы, а лишь проверяет, возможно ли это для заданного-s
.
Вариант 5
- Обязательный параметр, задающий путь до входного CSV-файла.
- Обязательный параметр, задающий путь до выходного CSV-файла.
- Аргумент
-a,--action
, принимающий только значения “width” или “height”. В зависимости от значения, добавляет в матрицу строку, состоящую из одинаковых чисел, равных ширине или высоте исходной матрицы. - Аргумент
-p,--prepend
, необязательный. Если указан, то строка добавляется не в конец матрицы, а в её начало.
Вариант 6
- Обязательный параметр, задающий путь до входного CSV-файла.
- Выходной файл не указывается, программа всегда перезаписывает входной CSV-файл.
- Аргумент
-r,--row
, задающий номер строки, над которой оперирует программа. - Аргумент
-e
, принимающий числовые значения, которыми программа должна заменять элементы указанной строки. Может повторяться несколько раз, т.е. аргументы-e 1 -e 2 -e 3
должны приводить к тому, что в строке первый, второй и третий элементы меняются на 1, 2 и 3, соответственно.
Вариант 7
- Аргумент
-i,--input
задаёт путь до входного CSV-файла. Обязательный аргумент. - Аргумент
-o,--output
задаёт путь до выходного CSV-файла. Если не указан - имя генерируется на основе входного файла. - Аргумент
-q,--quiet
, необязательный. Если он указан, то программа подавляет любые сообщения об ошибках. - Аргумент
-x
задаёт номер строки, над которым будет работать программа. Значение по умолчанию -1
. - Аргумент
-y
задаёт номер столбца, над которым будет работать программа. Значение по умолчанию -1
.
Программа зануляет элементы матрицы вокруг элемента, указанного через -x
и -y
.
Если квадрат, элементы которого зануляются, выходит за пределы матрицы (напр.
-x 0 -y 0
), то программа выдаёт ошибку.
Вариант 8
- Обязательный параметр, задающий путь до входного CSV-файла.
- Обязательный параметр, задающий путь до выходного CSV-файла.
- Аргумент
-v
. Если он указан, то программа выводит на экран промежуточные значения во время своей работы. - Аргумент
-s,--start
. Принимает числовое значение, на которое программа заменяет элементы главной диагонали матрицы, с каждым шагом увеличивая это значения на 1. Обязательный аргумент. - Аргумент
--stop
, необязательный. Принимает числовое значение, определяющее количество изменений, вносимых программой в матрицу. При значении0
должна заменяться вся диагональ. Значение по умолчанию -0
.
Вариант 9
- Обязательный параметр, задающий путь до входного CSV-файла.
- Выходной файл не указывается, программа всегда перезаписывает входной CSV-файл.
- Аргумент
-r1
, задающий номер строки, с которой программа начинает работу. - Аргумент
-r2
, задающий номер строки, с которой программа заканчивает работу. - Аргумент
-b,--backup
, определяющий, нужно ли создавать копию входного CSV-файла перед его перезаписью.
Программа суммирует строки от r1
до r2
поэлементно, а получившуюся строку
подставляет в матрицу вместо строк, использовавшихся для суммирования. Если
-r1
не указан, то программа использует строки от первой до r2
. Если -r2
не указан, то программа использует строки от r1
до последней.
Вариант 10
- Аргумент
-i,--input
задаёт путь до входного CSV-файла. Обязательный аргумент. - Аргумент
-o,--output
задаёт путь до выходного CSV-файла. Если не указан - имя генерируется на основе входного файла. - Обязательный параметр, принимающий лишь значения “r2c” и “c2r”. В зависимости от значения, производит транспонирование матрицы, переставляя строки на место столбцов, или наоборот.
- Аргумент
-q,--quiet
, необязательный. Если он указан, то программа подавляет любые сообщения об ошибках.
Вариант 11
- Обязательный параметр, задающий путь до входного CSV-файла.
- Обязательный параметр, задающий путь до выходного CSV-файла.
- Аргумент
-v
. Если он указан, то программа выводит на экран промежуточные значения во время своей работы. - Аргумент
-r,--row
. Задаёт номер элемента, на основании которого программа должна отсортировать строки матрицы. - Аргумент
-o,--order
, принимающий только значения “ascending” и “descending”. Определяет, будет ли сортировка производиться по возрастанию или по убыванию. Обязательный аргумент.
Вариант 12
- Обязательный параметр, задающий путь до входного CSV-файла.
- Выходной файл не указывается, программа всегда перезаписывает входной CSV-файл.
- Аргумент
-x1
задаёт номер строки, над которым будет работать программа. Значение по умолчанию -1
. - Аргумент
-y1
задаёт номер столбца, над которым будет работать программа. Значение по умолчанию -1
. - Аргумент
-x2
задаёт номер строки, над которым будет работать программа. Значение по умолчанию -1
. - Аргумент
-y2
задаёт номер столбца, над которым будет работать программа. Значение по умолчанию -1
.
Программа вырезает из матрицы прямоугольник элементов, левый верхний угол которого
имеет индекс (x1,y1)
, а правый нижний - (x2,y2)
. В выходной файл записывается
вырезанная подматрица. Программа не должна допускать вырезания единственного
элемента, если только не указан необязательный параметр -o
.
Вариант 13
- Аргумент
-i,--input
задаёт путь до входного CSV-файла. Обязательный аргумент. - Аргумент
-o,--output
задаёт путь до выходного CSV-файла. Если не указан - имя генерируется на основе входного файла. - Аргумент
-r,--row
задаёт номер строки матрицы, над которой будет работать программа. Значение по умолчанию -0
. - Аргумент
-d,--direction
принимает лишь значения “right” и “left” и задаёт направление сдвига аргумента-s
. - Аргумент
-s,--shift
задаёт на сколько нужно сдвинуть элементы внутри строки. Последний элемент при сдвиге вправо становится первым, и наоборот.
Вариант 14
- Обязательный параметр, задающий путь до входного CSV-файла.
- Обязательный параметр, задающий путь до выходного CSV-файла.
- Аргумент
-x
задаёт номер строки, над которым будет работать программа. Значение по умолчанию -1
. - Аргумент
-y
задаёт номер столбца, над которым будет работать программа. Значение по умолчанию -1
. - Аргумент
-n
, который может быть указан несколько раз, задаёт числа, количество которых программа должна подсчитать в квадрате вокруг элемента с индексами-x
и-y
. Этот элемент заменяется на количество найденных элементов. Если квадрат выходит за пределы матрицы (напр.-x 0 -y 0
), то программа выдаёт ошибку.
Вариант 15
- Обязательный параметр, задающий путь до входного CSV-файла.
- Выходной файл не указывается, программа всегда перезаписывает входной CSV-файл.
- Аргумент
-b,--backup
, определяющий, нужно ли создавать копию входного CSV-файла перед его перезаписью. - Аргумент
-f
, который может быть указан несколько раз, задаёт последовательность элементов, которую программа должна искать в каждой строке матрицы. При обнаружении последовательности строка удаляется. - Аргумент
-d
, необязательный. Если указан, программа лишь печатает номера строк, которые будут удалены, но не удаляет их.
