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. Смотрите Улучшена совместимость с оболочками для получения дополнительной информации. знаки пунктуации могут быть установлены только при создании экземпляра 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), результат остается в покое. В противном случае, если результатом является относительный путь, перед именем файла, находящегося непосредственно перед ним в стеке включения исходного кода, добавляется часть каталога (это похоже на то, как препроцессор C обрабатывает #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-символы, определенные в 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);

  • Экранирующие символы не распознаются;

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

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

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

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

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