shlex — Простой лексический анализ

Исходный код: Lib/shlex.py.


Класс shlex позволяет легко писать лексические анализаторы для простых синтаксисов, напоминающих синтаксис оболочки Unix. Это часто бывает полезно для написания мини-языков (например, в файлах управления запуском для приложений Python) или для разбора кавычек.

Модуль shlex определяет следующие функции:

shlex.split(s, comments=False, posix=True)

Разделить строку s, используя shell-подобный синтаксис. Если 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'

Возвращаемое значение имеет shell-эскейп для защиты от уязвимостей инъекций (см. quote()).

Добавлено в версии 3.8.

shlex.quote(s)

Возвращает версию строки s в формате shell. Возвращаемое значение - это строка, которую можно безопасно использовать в качестве одной лексемы в командной строке оболочки, в случаях, когда нельзя использовать список.

Предупреждение

Модуль 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 или экземпляр подкласса - это объект лексического анализатора. Аргумент инициализации, если он присутствует, указывает, откуда считывать символы. Это должен быть объект типа file-/stream с методами read() и readline() или строка. Если аргумент не указан, ввод будет осуществляться из sys.stdin. Вторым необязательным аргументом является строка с именем файла, которая задает начальное значение атрибута infile. Если аргумент instream опущен или равен sys.stdin, то второй аргумент по умолчанию принимает значение «stdin». Аргумент posix определяет режим работы: когда posix не является истиной (по умолчанию), экземпляр shlex будет работать в режиме совместимости. При работе в режиме POSIX, shlex будет стараться быть как можно ближе к правилам разбора оболочки POSIX. Аргумент punctuation_chars дает возможность сделать поведение еще ближе к тому, как разбирают настоящие оболочки. Он может принимать несколько значений: значение по умолчанию, False, сохраняет поведение, наблюдаемое в Python 3.5 и более ранних версиях. Если задано значение True, то изменяется разбор символов ();<>|&: любой ряд этих символов (считающихся знаками препинания) возвращается как одна лексема. Если задана непустая строка символов, то эти символы будут использоваться в качестве знаков препинания. Любые символы в атрибуте wordchars, которые появляются в punctuation_chars, будут удалены из wordchars. Дополнительную информацию см. в Улучшенная совместимость с оболочками. punctuation_chars может быть задан только при создании экземпляра shlex и не может быть изменен позднее.

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

См.также

Модуль configparser

Парсер для файлов конфигурации, аналогичных файлам Windows .ini.

шлекс Объекты

Экземпляр 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").

Результат манипуляций рассматривается как имя файла и возвращается в качестве первого компонента кортежа, а вызов open() приводит к появлению второго компонента. (Примечание: это обратный порядок аргументов при инициализации экземпляра!)

Этот хук открыт для того, чтобы вы могли использовать его для реализации путей поиска по каталогам, добавления расширений файлов и других хаков пространства имен. Соответствующего хука „close“ не существует, но экземпляр shlex будет вызывать метод close() для исходного входного потока, когда он вернет EOF.

Для более явного управления суммированием источников используйте методы push_source() и pop_source().

shlex.push_source(newstream, newfile=None)

Переместить поток источника ввода в стек ввода. Если указан аргумент filename, то впоследствии он будет доступен для использования в сообщениях об ошибках. Это тот же метод, который используется внутри метода 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

Символы, которые будут рассматриваться как 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, и в None в режиме POSIX.

shlex.punctuation_chars

Свойство, доступное только для чтения. Символы, которые будут считаться пунктуацией. Ряды знаков препинания будут возвращены как один токен. Однако, обратите внимание, что семантическая проверка валидности не будет выполнена: например, „>>>“ может быть возвращен как лексема, хотя он может быть не распознан как таковой оболочками.

Добавлено в версии 3.6.

Правила синтаксического анализа

При работе в режиме, отличном от POSIX, shlex будет стараться подчиняться следующим правилам.

  • Символы кавычек не распознаются внутри слов (Do"Not"Separate разбирается как одно слово Do"Not"Separate);

  • Символы Escape не распознаются;

  • Заключение символов в кавычки сохраняет буквальное значение всех символов внутри кавычек;

  • Закрывающие кавычки разделяют слова ("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', ')']

Конечно, будут возвращены токены, которые не являются действительными для shells, и вам нужно будет реализовать свои собственные проверки на ошибки для возвращаемых токенов.

Вместо передачи 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).

Вернуться на верх