Spec-Zone.ru › Python 3.14

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 работает в режиме совместимости. В режиме POSIX shlex старается как можно точнее следовать правилам разбора оболочки POSIX. Аргумент punctuation_chars позволяет ещё больше приблизить поведение к разбору в настоящих оболочках. Он может принимать несколько значений: значение по умолчанию, False, сохраняет поведение, существовавшее в Python 3.5 и более ранних версиях. Если задано значение True, разбор символов ();<>|& изменяется: любая последовательность таких символов (считающихся знаками пунктуации) возвращается как один токен. Если задана непустая строка символов, эти символы будут использоваться как знаки пунктуации. Символы атрибута wordchars, входящие в punctuation_chars, будут удалены из wordchars. Подробнее см. в разделе Повышенная совместимость с оболочками. Параметр punctuation_chars можно задать только при создании экземпляра shlex; впоследствии его нельзя изменить.

Изменено в версии 3.6: Добавлен параметр punctuation_chars.

См. также

Module configparser

Парсер файлов конфигурации, похожих на файлы .ini Windows.

Объекты 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API