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().text>>> 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.Этот способ небезопасен:
text>>> filename = 'somefile; rm -rf ~' >>> command = 'ls -l {}'.format(filename) >>> print(command) # выполнено через оболочку: бум! ls -l somefile; rm -rf ~quote()позволяет закрыть эту брешь в безопасности:text>>> 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():text>>> 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 не является истинным (по умолчанию), экземплярshlexбудет работать в режиме совместимости. При работе в режиме POSIXshlexстарается максимально приблизиться к правилам разбора оболочки POSIX. Аргумент punctuation_chars позволяет сделать поведение ещё более близким к тому, как реальные оболочки выполняют разбор. Он может принимать несколько значений: значение по умолчаниюFalseсохраняет поведение, наблюдаемое в Python 3.5 и более ранних версиях. Если заданоTrue, то разбор символов();<>|&изменяется: любая последовательность этих символов (считающихся знаками пунктуации) возвращается как единый токен. Если задана непустая строка символов, эти символы будут использоваться как знаки пунктуации. Любые символы из атрибутаwordchars, которые присутствуют в punctuation_chars, будут удалены изwordchars. См. Улучшенная совместимость с оболочками для получения дополнительной информации. punctuation_chars можно задать только при создании экземпляраshlex, и позже его нельзя изменить.Изменено в версии 3.6: Добавлен параметр punctuation_chars.
Смотрите также
- Модуль
configparser Парсер для конфигурационных файлов, похожих на файлы
.iniв Windows.
shlex ObjectsОбъекты shlex
Экземпляр shlex имеет следующие методы:
- shlex.get_token()¶
Возвращает токен. Если токены были помещены в стек с помощью
push_token(), извлекает токен из стека. В противном случае читает один токен из входного потока. Если при чтении сразу встречается конец файла, возвращаетсяeof(пустая строка ('') в не-POSIX режиме иNoneв режиме POSIX).
- shlex.push_token(str)¶
Помещает аргумент в стек токенов.
- shlex.read_token()¶
Читает необработанный токен. Игнорирует стек pushback и не обрабатывает запросы источников. (Обычно это не является полезной точкой входа и документируется здесь только для полноты.)
- shlex.sourcehook(filename)¶
Когда
shlexобнаруживает запрос источника (см.sourceниже), этому методу передаётся следующий токен в качестве аргумента, и ожидается, что он вернёт кортеж из имени файла и открытого файлоподобного объекта.Обычно этот метод сначала удаляет кавычки из аргумента. Если результат является абсолютным путём, или не было предыдущего активного запроса источника, или предыдущий источник был потоком (например,
sys.stdin), результат остаётся без изменений. В противном случае, если результат является относительным путём, к нему добавляется каталог файла, находящегося непосредственно перед ним в стеке включения источников (это поведение аналогично тому, как препроцессор C обрабатывает#include "file.h").Результат манипуляций рассматривается как имя файла и возвращается как первый компонент кортежа, при этом
open()вызывается для него, чтобы получить второй компонент. (Примечание: это обратный порядок аргументов при инициализации экземпляра!)Этот хук предоставляется, чтобы вы могли использовать его для реализации путей поиска в каталогах, добавления расширений файлов и других трюков с пространствами имён. Соответствующего хука закрытия нет, но экземпляр 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¶
Символы, которые будут считаться escape-символами. Это используется только в режиме POSIX и по умолчанию включает только
'\'.
- shlex.quotes¶
Символы, которые будут считаться кавычками строк. Токен накапливается до тех пор, пока не встретится такая же кавычка (таким образом, разные типы кавычек защищают друг друга, как в оболочке). По умолчанию включает одинарные и двойные кавычки ASCII.
- shlex.escapedquotes¶
Символы в
quotes, которые будут интерпретировать escape-символы, определённые вescape. Это используется только в режиме POSIX и по умолчанию включает только'"'.
- shlex.whitespace_split¶
Если
True, токены будут разделяться только по пробельным символам. Это полезно, например, для разбора командных строк с помощьюshlex, получая токены аналогично аргументам оболочки. При использовании в сочетании сpunctuation_charsтокены будут разделяться по пробельным символам в дополнение к этим символам.Изменено в версии 3.8: Атрибут
punctuation_charsбыл сделан совместимым с атрибутомwhitespace_split.
- shlex.infile¶
Имя текущего входного файла, задаваемое при создании экземпляра класса или добавляемое в стек последующими запросами источника. Может быть полезно при построении сообщений об ошибках.
- shlex.source¶
По умолчанию этот атрибут равен
None. Если присвоить ему строку, эта строка будет распознаваться как запрос включения на лексическом уровне, аналогично ключевому словуsourceв различных оболочках. То есть следующий за ним токен будет открыт как имя файла, и ввод будет браться из этого потока до конца файла, после чего будет вызван методclose()этого потока, и источником ввода снова станет исходный поток. Запросы источника могут складываться в стек на любую глубину.
- shlex.debug¶
Если этот атрибут является числовым и больше или равен
1, экземплярshlexбудет выводить подробную информацию о своих действиях. Если вам нужно использовать это, прочитайте исходный код модуля для изучения деталей.
- shlex.lineno¶
Номер строки источника (количество встреченных символов новой строки плюс один).
- shlex.token¶
Буфер токена. Может быть полезен при перехвате исключений.
- shlex.eof¶
Токен, используемый для определения конца файла. В не-POSIX режиме он устанавливается в пустую строку (
''), а в POSIX-режиме – вNone.
- shlex.punctuation_chars¶
Свойство только для чтения. Символы, которые считаются знаками пунктуации. Последовательности знаков пунктуации будут возвращаться как один токен. Однако обратите внимание, что семантическая корректность не проверяется: например, ‘>>>’ может быть возвращён как токен, даже если оболочки его не распознают.
Добавлено в версии 3.6.
Parsing RulesПравила разбора
При работе в не-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;Пустые строки в кавычках (
'') разрешены.
Improved Compatibility with ShellsУлучшенная совместимость с оболочками
Добавлено в версии 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.)