Spec-Zone.ru › Python 3.12

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» нет, но при достижении 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

Spec-Zone.ru

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