shlex — Простой лексический анализ
Исходный код: Lib/shlex.py
Класс shlex упрощает написание лексических анализаторов для простых синтаксисов, подобных синтаксису оболочки Unix. Он часто бывает полезен при написании мини-языков (например, в файлах управления запуском приложений Python) или при разборе строк в кавычках.
Модуль shlex определяет следующие функции:
-
shlex.split(s, comments=False, posix=True) -
Разбивает строку s, используя синтаксис, подобный синтаксису оболочки. Если comments имеет значение
False(по умолчанию), разбор комментариев в данной строке будет отключён (атрибутуcommentersэкземпляраshlexприсваивается пустая строка). По умолчанию эта функция работает в режиме POSIX, но использует режим не POSIX, если аргумент posix имеет ложное значение.Изменено в версии 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разделяет слова только пробельными символами; - EOF обозначается пустой строкой (
''); - Разбирать пустые строки невозможно, даже если они заключены в кавычки.
В режиме POSIX shlex старается соблюдать следующие правила разбора.
- Кавычки удаляются и не разделяют слова (
"Do"Not"Separate"разбирается как одно словоDoNotSeparate); - Символы экранирования вне кавычек (например,
'\') сохраняют буквальное значение следующего за ними символа; - Заключение символов в кавычки, не входящие в
escapedquotes(например,"'"), сохраняет буквальные значения всех символов внутри кавычек; - Заключение символов в кавычки, входящие в
escapedquotes(например,'"'), сохраняет буквальные значения всех символов внутри кавычек, за исключением символов, указанных вescape. Символы экранирования сохраняют особое значение только тогда, когда за ними следует используемая кавычка или сам символ экранирования. В противном случае символ экранирования считается обычным символом. - EOF обозначается значением
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?']
Однако для максимально точного соответствия поведению оболочки рекомендуется всегда использовать posix и whitespace_split при использовании punctuation_chars, что полностью отключит действие wordchars.
Для наилучшего результата punctuation_chars следует задавать совместно с posix=True. (Обратите внимание, что posix=False используется по умолчанию для shlex.)
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/shlex.html