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.Изменено в версии 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'
Возвращаемое значение имеет shell-эскейп для защиты от инъекционных уязвимостей (см.
quote()
).Added in version 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 ~']
Added in version 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
будет работать в режиме совместимости. При работе в режиме POSIXshlex
будет стараться быть как можно ближе к правилам разбора оболочки 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()¶
Прочитайте необработанный токен. Игнорируйте стек pushback и не интерпретируйте исходные запросы. (Обычно это не является полезной точкой входа и документируется здесь только для полноты картины).
- shlex.sourcehook(filename)¶
Когда
shlex
обнаруживает запрос источника (см.source
ниже), этот метод получает в качестве аргумента следующую лексему и должен вернуть кортеж, состоящий из имени файла и объекта типа open file.Обычно этот метод сначала удаляет все кавычки из аргумента. Если результат является абсолютным именем пути, или не было предыдущего запроса источника, или предыдущий источник был потоком (например,
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¶
Символы, которые будут считаться экранирующими. Это будет использоваться только в режиме 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.source¶
По умолчанию этот атрибут имеет значение
None
. Если присвоить ему строку, то эта строка будет распознаваться как запрос на включение на лексическом уровне, подобно ключевому словуsource
в различных оболочках. То есть следующий сразу за ней токен будет открыт как имя файла, и ввод будет осуществляться из этого потока до EOF, после чего будет вызван методclose()
этого потока, и источник ввода снова станет исходным потоком ввода. Запросы источника могут быть сложены на любое количество уровней в глубину.
- shlex.debug¶
Если этот атрибут имеет числовое значение
1
или больше, то экземплярshlex
будет выводить подробную информацию о своем поведении. Если вам нужно использовать это, вы можете прочитать исходный код модуля, чтобы узнать подробности.
- shlex.lineno¶
Номер строки источника (количество новых строк, просмотренных до сих пор, плюс одна).
- shlex.token¶
Буфер маркера. Может быть полезно проверить его при отлове исключений.
- shlex.eof¶
Токен, используемый для определения конца файла. В режиме, отличном от POSIX, он принимает значение пустой строки (
''
), а в режиме POSIX - значениеNone
.
- shlex.punctuation_chars¶
Свойство, доступное только для чтения. Символы, которые будут считаться пунктуацией. Ряды знаков препинания будут возвращены как один токен. Однако обратите внимание, что проверка семантической валидности не производится: например, „>>>“ может быть возвращена как лексема, хотя она может быть не распознана shell’ом как таковая.
Added in version 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
;Допускаются пустые строки в кавычках (
''
).
Улучшенная совместимость с оболочками¶
Added in version 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
).