shlex — Простая лексическая обработка
Исходный код: Lib/shlex.py
Класс shlex упрощает создание лексических анализаторов для простых синтаксисов, напоминающих синтаксис оболочки Unix. Это часто бывает полезно при написании мини-языков (например, в файлах управления запусками для приложений Python) или для разбора строковых литералов.
Модуль shlex определяет следующие функции:
-
shlex.split(s, comments=False, posix=True) -
Разделяет строку s, используя синтаксис, подобный оболочке. Если comments имеет значение
False(по умолчанию), то разбор комментариев в данной строке будет отключён (атрибутcommentersэкземпляраshlexбудет установлен в пустую строку). Эта функция работает в режиме POSIX по умолчанию, но использует режим не-POSIX, если аргумент posix равен False.Примечание
Поскольку функция
split()создаёт экземплярshlex, передачаNoneдля s будет читать строку для разделения из стандартного ввода.Устарело начиная с версии 3.9: Передача
Noneдля s в будущих версиях Python приведёт к исключению.
-
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будет работать в режиме совместимости. При работе в режиме POSIX,shlexбудет пытаться максимально соответствовать правилам разбора оболочки POSIX. Аргумент punctuation_chars предоставляет возможность ещё большего соответствия реальным оболочкам. Он может принимать несколько значений: значение по умолчанию,False, сохраняет поведение, наблюдаемое в Python 3.5 и ранее. Если установлено значениеTrue, то разбор символов();<>|&изменится: любая последовательность этих символов (считаемых знаками пунктуации) возвращается как один токен. Если установлено ненулевое строковое значение, то эти символы будут использоваться в качестве знаков пунктуации. Любые символы из атрибутаwordchars, которые присутствуют в punctuation_chars, будут удалены из атрибутаwordchars. Дополнительная информация приведена в разделе Улучшенная совместимость с оболочками. punctuation_chars может быть установлен только при создании экземпляраshlexи не может быть изменён позднее.Изменено в версии 3.6: Добавлен параметр punctuation_chars.
См. также
-
Moduleconfigparser -
Парсер для файлов конфигурации, похожий на файлы конфигурации Windows
.ini.
Объекты shlex
У экземпляра shlex есть следующие методы:
-
shlex.get_token() -
Возвращает токен. Если токены были помещены в стек с помощью
push_token(), токен извлекается из стека. В противном случае считывается токен из входного потока. Если чтение встречает немедленный конец файла, возвращаетсяeof(пустая строка ('') в режиме non-POSIX иNoneв режиме POSIX).
-
shlex.push_token(str) -
Поместить аргумент в стек токенов.
-
shlex.read_token() -
Считать сырой токен. Игнорировать стек отложенных токенов и не интерпретировать запросы на включение исходного кода. (Это обычно не является полезной точкой входа и документируется здесь только ради полноты.)
-
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) -
Этот метод генерирует префикс сообщения об ошибке в формате метки ошибки компилятора Unix C; формат
'"%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 -
Токен, используемый для определения конца файла. Он будет установлен в пустую строку (
'') в режиме non-POSIX и вNoneв режиме POSIX.
-
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?']
Однако, чтобы как можно точнее воспроизвести поведение оболочки, рекомендуется всегда использовать posix и whitespace_split при использовании punctuation_chars, что полностью отменит wordchars.
Для наилучшего результата punctuation_chars должно быть установлено в сочетании с posix=True. (Обратите внимание, что posix=False является значением по умолчанию для shlex.)
© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/shlex.html