shlex — простой лексический анализ
Исходный код: Lib/shlex.py
Класс shlex упрощает написание лексических анализаторов для простых синтаксисов, похожих на синтаксис оболочки Unix. Это часто полезно при создании мини-языков (например, в файлах управления запуском приложений Python) или при разборе строк в кавычках.
Модуль shlex определяет следующие функции:
-
shlex.split(s, comments=False, posix=True) -
Разбивает строку s с использованием синтаксиса, похожего на синтаксис оболочки. Если comments равно
False(значение по умолчанию), разбор комментариев в заданной строке отключается (атрибутcommentersэкземпляраshlexустанавливается в пустую строку). По умолчанию эта функция работает в режиме POSIX, но использует режим, отличный от POSIX, если аргумент posix имеет значение false.Изменено в версии 3.12: Передача
Noneв качестве аргумента s теперь вызывает исключение, а не приводит к чтению изsys.stdin.
-
shlex.join(split_command) -
Объединяет токены списка split_command и возвращает строку. Эта функция является обратной для
split().>>> from shlex import join >>> print(join(['echo', '-n', 'Multiple words'])) echo -n 'Multiple words'
Возвращаемое значение экранируется для оболочки, чтобы защитить от уязвимостей, связанных с инъекциями (см.
quote()).Добавлено в версии 3.8.
-
shlex.quote(s) -
Возвращает экранированную для оболочки версию строки s. Возвращаемое значение — это строка, которую можно безопасно использовать как один токен в командной строке оболочки, если вы не можете использовать список.
Предупреждение
Модуль
shlexпредназначен только для оболочек Unix.Функция
quote()не гарантирует корректную работу с оболочками, не соответствующими POSIX, или оболочками других операционных систем, например Windows. Выполнение команд, экранированных этим модулем, в таких оболочках может создать возможность для уязвимости, связанной с инъекцией команд.Рассмотрите возможность использования функций, передающих аргументы команды в виде списков, например
subprocess.run()сshell=False.Следующий идиоматичный пример небезопасен:
>>> filename = 'somefile; rm -rf ~' >>> command = 'ls -l {}'.format(filename) >>> print(command) # executed by a shell: boom! ls -l somefile; rm -rf ~Функция
quote()позволяет устранить уязвимость:>>> from shlex import quote >>> command = 'ls -l {}'.format(quote(filename)) >>> print(command) ls -l 'somefile; rm -rf ~' >>> remote_command = 'ssh home {}'.format(quote(command)) >>> print(remote_command) ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''Экранирование совместимо с оболочками UNIX и с
split():>>> from shlex import split >>> remote_command = split(remote_command) >>> remote_command ['ssh', 'home', "ls -l 'somefile; rm -rf ~'"] >>> command = split(remote_command[-1]) >>> command ['ls', '-l', 'somefile; rm -rf ~']
Добавлено в версии 3.3.
Модуль shlex определяет следующий класс:
-
class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False) -
Экземпляр
shlexили его подкласса — это объект лексического анализатора. Аргумент инициализации, если он задан, указывает, откуда считывать символы. Это должен быть объект, подобный файлу или потоку, с методамиread()иreadline(), либо строка. Если аргумент не задан, ввод будет выполняться изsys.stdin. Второй необязательный аргумент — это строка с именем файла, которая задаёт начальное значение атрибутаinfile. Если аргумент instream опущен или равенsys.stdin, значением второго аргумента по умолчанию будет «stdin». Аргумент posix задаёт режим работы: если posix не равен true (значение по умолчанию), экземплярshlexработает в режиме совместимости. В режиме POSIXshlexстарается как можно точнее следовать правилам разбора оболочки POSIX. Аргумент punctuation_chars позволяет ещё больше приблизить поведение к разбору в настоящих оболочках. Он может принимать несколько значений: значение по умолчанию,False, сохраняет поведение, существовавшее в Python 3.5 и более ранних версиях. Если задано значениеTrue, разбор символов();<>|&изменяется: любая последовательность таких символов (считающихся знаками пунктуации) возвращается как один токен. Если задана непустая строка символов, эти символы будут использоваться как знаки пунктуации. Символы атрибутаwordchars, входящие в punctuation_chars, будут удалены изwordchars. Подробнее см. в разделе Повышенная совместимость с оболочками. Параметр punctuation_chars можно задать только при создании экземпляраshlex; впоследствии его нельзя изменить.Изменено в версии 3.6: Добавлен параметр punctuation_chars.
См. также
-
Moduleconfigparser -
Парсер файлов конфигурации, похожих на файлы
.iniWindows.
Объекты shlex
Экземпляр shlex имеет следующие методы:
-
shlex.get_token() -
Возвращает токен. Если токены были помещены в стек с помощью
push_token(), извлекает токен из стека. В противном случае считывает токен из входного потока. Если при чтении немедленно обнаруживается конец файла, возвращаетсяeof(пустая строка ('') в режиме, отличном от POSIX, иNoneв режиме POSIX).
-
shlex.push_token(str) -
Помещает аргумент в стек токенов.
-
shlex.read_token() -
Считывает необработанный токен. Игнорирует стек возврата и не обрабатывает запросы на подключение источников. (Обычно этот метод не представляет практической ценности; здесь он описан лишь для полноты.)
-
shlex.sourcehook(filename) -
Когда
shlexобнаруживает запрос на подключение источника (см.sourceниже), этот метод получает в качестве аргумента следующий токен и должен вернуть кортеж, состоящий из имени файла и открытого файлового объекта.Обычно этот метод сначала удаляет кавычки из аргумента. Если результат представляет собой абсолютный путь, если ранее не было запросов на подключение источника или если предыдущий источник был потоком (например,
sys.stdin), результат остаётся без изменений. В противном случае, если результат представляет собой относительный путь, к нему добавляется каталог из имени файла, который непосредственно предшествует ему в стеке включения источников (это поведение аналогично обработке#include "file.h"препроцессором C).Результат этих преобразований трактуется как имя файла и возвращается в качестве первого элемента кортежа; для получения второго элемента к нему применяется
open(). (Примечание: порядок аргументов здесь обратный порядку при инициализации экземпляра!)Этот хук доступен для реализации путей поиска каталогов, добавления расширений файлов и других приёмов работы с пространствами имён. Соответствующего хука «close» нет, но экземпляр shlex вызывает метод
close()потока подключённого источника при достижении EOF.Для более явного управления стеком источников используйте методы
push_source()иpop_source().
-
shlex.push_source(newstream, newfile=None) -
Помещает поток входного источника в стек ввода. Если задан аргумент с именем файла, это имя впоследствии будет доступно для использования в сообщениях об ошибках. Это тот же метод, который внутренне используется методом
sourcehook().
-
shlex.pop_source() -
Извлекает из стека ввода последний помещённый в него источник ввода. Это тот же метод, который внутренне используется при достижении лексическим анализатором EOF во вложенном входном потоке.
-
shlex.error_leader(infile=None, lineno=None) -
Этот метод формирует начало сообщения об ошибке в формате метки ошибки компилятора C для Unix; формат имеет вид
'"%s", line %d: ', где%sзаменяется именем текущего исходного файла, а%d— номером текущей строки ввода (эти значения можно переопределить необязательными аргументами).Этот вспомогательный метод предназначен для того, чтобы побуждать пользователей
shlexсоздавать сообщения об ошибках в стандартном формате, который можно анализировать с помощью Emacs и других инструментов Unix.
Экземпляры подклассов shlex имеют несколько открытых переменных экземпляра, которые управляют лексическим анализом или могут использоваться для отладки:
-
shlex.commenters -
Строка символов, распознаваемых как начало комментария. Все символы от начала комментария до конца строки игнорируются. По умолчанию включает только
'#'.
-
shlex.wordchars -
Строка символов, которые объединяются в многосимвольные токены. По умолчанию включает все буквы и цифры ASCII, а также символ подчёркивания. В режиме POSIX также включаются символы с диакритическими знаками из набора Latin-1. Если атрибут
punctuation_charsне пуст, символы~-./*?=, которые могут встречаться в спецификациях имён файлов и параметрах командной строки, также будут включены в этот атрибут, а символы, входящие вpunctuation_chars, будут удалены изwordchars, если они там присутствуют. Если дляwhitespace_splitзадано значениеTrue, это не будет иметь эффекта.
-
shlex.whitespace -
Символы, которые считаются пробельными и пропускаются. Пробельные символы разделяют токены. По умолчанию включает пробел, табуляцию, перевод строки и возврат каретки.
-
shlex.escape -
Символы, которые считаются символами экранирования. Используются только в режиме POSIX; по умолчанию включает только
'\'.
-
shlex.quotes -
Символы, которые считаются кавычками для строк. Токен накапливается до тех пор, пока снова не встретится такая же кавычка (таким образом, разные типы кавычек защищают содержимое друг друга, как в оболочке). По умолчанию включает одинарную и двойную кавычки ASCII.
-
shlex.escapedquotes -
Символы из
quotes, которые интерпретируют символы экранирования, определённые вescape. Используется только в режиме POSIX; по умолчанию включает только'"'.
-
shlex.whitespace_split -
Если значение равно
True, токены будут разделяться только по пробельным символам. Это полезно, например, для разбора командных строк с помощьюshlex, чтобы получать токены аналогично аргументам оболочки. При использовании совместно сpunctuation_charsтокены будут разделяться по пробельным символам и указанным знакам пунктуации.Изменено в версии 3.8: Атрибут
punctuation_charsстал совместим с атрибутомwhitespace_split.
-
shlex.infile -
Имя текущего входного файла, заданное при создании экземпляра класса или добавленное последующими запросами на подключение источника. Может быть полезно при формировании сообщений об ошибках.
-
shlex.instream -
Входной поток, из которого этот экземпляр
shlexсчитывает символы.
-
shlex.source -
По умолчанию этому атрибуту присвоено значение
None. Если присвоить ему строку, она будет распознаваться как запрос лексического уровня на включение источника, аналогичный ключевому словуsourceв различных оболочках. То есть следующий токен будет открыт как имя файла, и ввод будет считываться из этого потока до EOF; в этот момент будет вызван методclose()этого потока, а исходным потоком ввода снова станет первоначальный. Запросы на подключение источников можно вкладывать на любую глубину.
-
shlex.debug -
Если значение этого атрибута является числом не меньше
1, экземплярshlexбудет выводить подробную информацию о ходе работы. Если вам нужно это использовать, подробности можно узнать из исходного кода модуля.
-
shlex.lineno -
Номер строки источника (количество обнаруженных переводов строки плюс один).
-
shlex.token -
Буфер токена. Может быть полезно просмотреть его при перехвате исключений.
-
shlex.eof -
Токен, используемый для определения конца файла. В режиме, отличном от POSIX, ему присваивается пустая строка (
''), а в режиме POSIX —None.
-
shlex.punctuation_chars -
Свойство только для чтения. Символы, которые считаются знаками пунктуации. Последовательности знаков пунктуации возвращаются как один токен. Однако обратите внимание, что проверка семантической корректности не выполняется: например, ‘>>>’ может быть возвращён как токен, хотя оболочки могут не распознавать его как таковой.
Добавлено в версии 3.6.
Правила разбора
В режиме, отличном от POSIX, shlex старается следовать следующим правилам.
- Кавычки не распознаются внутри слов (
Do"Not"Separateразбирается как одно словоDo"Not"Separate); - Символы экранирования не распознаются;
- Заключение символов в кавычки сохраняет буквальные значения всех символов внутри кавычек;
- Закрывающие кавычки разделяют слова (
"Do"Separateразбирается как"Do"иSeparate); - Если
whitespace_splitравноFalse, любой символ, не объявленный символом слова, пробельным символом или кавычкой, возвращается как односимвольный токен. Если оно равноTrue,shlexразделяет слова только по пробельным символам; - Конец файла обозначается пустой строкой (
''); - Разобрать пустые строки, даже заключённые в кавычки, невозможно.
В режиме POSIX shlex старается следовать следующим правилам разбора.
- Кавычки удаляются и не разделяют слова (
"Do"Not"Separate"разбирается как одно словоDoNotSeparate); - Не заключённые в кавычки символы экранирования (например,
'\') сохраняют буквальное значение следующего за ними символа; - Заключение символов в кавычки, не входящие в
escapedquotes(например,"'"), сохраняет буквальные значения всех символов внутри кавычек; - Заключение символов в кавычки, входящие в
escapedquotes(например,'"'), сохраняет буквальные значения всех символов внутри кавычек, за исключением символов, указанных вescape. Символы экранирования сохраняют специальное значение только тогда, когда за ними следует используемая кавычка или сам символ экранирования. В остальных случаях символ экранирования считается обычным символом. - Конец файла обозначается значением
None; - Допускаются пустые строки в кавычках (
'').
Повышенная совместимость с оболочками
Добавлено в версии 3.6.
Класс shlex обеспечивает совместимость с разбором, выполняемым распространёнными оболочками Unix, такими как bash, dash и sh. Чтобы воспользоваться этой совместимостью, укажите аргумент punctuation_chars в конструкторе. По умолчанию ему присваивается значение False, которое сохраняет поведение до версии 3.6. Однако если ему присвоить значение True, разбор символов ();<>|& изменится: любая последовательность этих символов будет возвращаться как один токен. Хотя это и не полноценный парсер оболочек (его разработка выходила бы за рамки стандартной библиотеки из-за разнообразия существующих оболочек), такой подход позволяет легче обрабатывать командные строки. Разницу можно увидеть в следующем фрагменте:
>>> import shlex
>>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
>>> s = shlex.shlex(text, posix=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
>>> s = shlex.shlex(text, posix=True, punctuation_chars=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
'(', 'def', 'ghi', ')']
Разумеется, будут возвращаться токены, недопустимые для оболочек, и вам потребуется самостоятельно проверять возвращённые токены на ошибки.
Вместо передачи True в качестве значения параметра punctuation_chars можно передать строку с конкретными символами, которые будут определять, какие символы считаются знаками пунктуации. Например:
>>> import shlex
>>> s = shlex.shlex("a && b || c", punctuation_chars="|")
>>> list(s)
['a', '&', '&', 'b', '||', 'c']
Примечание
Если указан параметр punctuation_chars, атрибут wordchars дополняется символами ~-./*?=. Это связано с тем, что эти символы могут встречаться в именах файлов (в том числе в шаблонах подстановки) и аргументах командной строки (например, --color=auto). Поэтому:
>>> import shlex
>>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
... punctuation_chars=True)
>>> list(s)
['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']
Однако для максимально точного соответствия оболочке при использовании punctuation_chars рекомендуется всегда использовать posix и whitespace_split, что полностью нейтрализует действие wordchars.
Для достижения наилучшего результата punctuation_chars следует задавать вместе с posix=True. (Обратите внимание, что posix=False используется по умолчанию для shlex.)
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/shlex.html