shlex
— Простой лексический анализ¶
Класс shlex
упрощает написание лексических анализаторов для
простых синтаксисов, напоминающих синтаксис оболочки Unix. Это часто бывает
полезно для написания мини-языков (например, в файлах управления запуском для
Python приложений) или для парсинга строк в кавычках.
Модуль shlex
определяет следующие функции:
-
shlex.
split
(s, comments=False, posix=True)¶ Разделяет строку s, используя синтаксис оболочки. Если comments равен
False
(по умолчанию), анализ комментариев в данной строке будет отключён (установка атрибутаcommenters
экземпляраshlex
на пустую строку). Данная функция работает в режиме POSIX по умолчанию, но использует отличный от POSIX режим, если у аргумента posix ложное значение.
-
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. Возвращаемое значение представляет собой строку, которую можно безопасно использовать как один токен в командной строке оболочки в случаях, когда вы не можете использовать список.
Данная идиома была бы небезопасной:
>>> filename = 'somefile; rm -rf ~' >>> command = 'ls -l {}'.format(filename) >>> print(command) # выполнен оболочкой: бум! 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 не равно истина (по умолчанию), экземплярshlex
будет работать в режиме совместимости. При работе в режиме POSIXshlex
попытается максимально приблизиться к правилам парсинга оболочки POSIX. Аргумент punctuation_chars позволяет сделать поведение ещё ближе к тому, как разбираются настоящие оболочки. Это может принимать несколько значений: значение по умолчанию,False
, сохраняет поведение, наблюдаемое в Python 3.5 и более ранних версиях. Если установлено значениеTrue
, то парсинг символов();<>|&
изменяется: любая серия данных символов (считающихся знаками препинания) возвращается как один токен. Если задана непустая строка символов, данные символы будут использоваться в качестве знаков препинания. Любые символы в атрибутеwordchars
, которые появляются в punctuation_chars, будут удалены изwordchars
. См. Улучшена совместимость с оболочками для получения дополнительной информации. punctuation_chars может быть установлен только при создании экземпляраshlex
и не может быть изменён позже.Изменено в версии 3.6: Добавлен параметр punctuation_chars.
См.также
- Модуль
configparser
- Парсер для файлов конфигурации, похожих на
.ini
файлы Windows.
Объекты shlex¶
У экземпляра shlex
есть следующие методы:
-
shlex.
get_token
()¶ Возвращает токен. Если токены были сложены с помощью
push_token()
, извлекает токен из стека. В противном случае читает один из входного потока. Если при чтении обнаруживается немедленный конец файла, возвращаетсяeof
(пустая строка (''
) в режиме, отличном от POSIX, иNone
в режиме POSIX).
-
shlex.
push_token
(str)¶ Поместить аргумент в стек токенов.
-
shlex.
read_token
()¶ Чтение необработанного токена. Игнорировать стек pushback и не интерпретирует исходные запросы. (Обычно это не очень полезная точка входа, и она задокументирована здесь только для полноты картины.)
-
shlex.
sourcehook
(filename)¶ Когда
shlex
обнаруживает исходный запрос (см.source
ниже), этому методу в качестве аргумента передаётся следующий токен, и ожидается, что он вернёт кортеж, состоящий из имени файла и открытого файлового объекта.Обычно данный метод сначала удаляет из аргумента все кавычки. Если результатом является абсолютный путь, или предыдущий запрос источника не действовал, или предыдущий источник был потоком (например,
sys.stdin
), результат остаётся без изменений. В противном случае, если результатом является относительный путь к имени файла, непосредственно предшествующему ему в стеке включения исходного кода, добавляется часть каталога (это поведение похоже на то, как препроцессор C обрабатывает#include "file.h"
).Результат манипуляций обрабатывается как имя файла и возвращается как первый компонент кортежа с вызовом
open()
для получения второго компонента. (Примечание: это обратный порядок аргументов при инициализации экземпляра!)Данный хук открыт, так что вы можете использовать его для реализации путей поиска каталогов, добавления расширений файлов и других хаков пространства имён. Соответствующего хука «закрыть» нет, но экземпляр 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)¶ Данный метод создаёт заголовок сообщения об ошибке в формате метки ошибки компилятора 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, и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
. Экранирующие символы сохраняют свое особое значение только тогда, когда за ними следует используемая кавычка или сам экранирующий символ. В противном случае 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
.)