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» нет, но при достижении EOF экземпляр shlex вызовет метод
close()потока подключённого источника.Для более явного управления стеком источников используйте методы
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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/shlex.html