> **Источник:** https://python-all.ru/3.5/library/shlex.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 24.3. [`shlex`](https://python-all.ru/3.5/library/shlex.html#module-shlex) – Простой лексический анализ

**Исходный код:** [Lib/shlex.py](https://python-all.ru/src/3.5/Lib/shlex.py)

---

Класс [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) упрощает написание лексических анализаторов для синтаксиса, напоминающего синтаксис оболочки Unix. Это часто бывает полезно для создания мини-языков (например, в конфигурационных файлах приложений Python) или для разбора строк в кавычках.

Модуль [`shlex`](https://python-all.ru/3.5/library/shlex.html#module-shlex) определяет следующие функции:

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

Разделяет строку *s*, используя синтаксис, подобный оболочке. Если *comments* равно [`False`](https://python-all.ru/3.5/library/constants.html#False) (по умолчанию), разбор комментариев в заданной строке будет отключён (устанавливает атрибут [`commenters`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.commenters) экземпляра [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) в пустую строку). Эта функция работает в режиме POSIX по умолчанию, но использует не-POSIX режим, если аргумент *posix* равен False.

> **Примечание**
>
> Поскольку функция [`split()`](https://python-all.ru/3.5/library/shlex.html#shlex.split) создаёт экземпляр [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) , передача `None` в качестве *s* будет читать строку для разбиения из стандартного ввода.

#### `shlex.quote(s)`

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

Этот подход был бы небезопасен:

```python
>>> filename = 'somefile; rm -rf ~'
>>> command = 'ls -l {}'.format(filename)
>>> print(command)  # выполнено оболочкой: бабах!
ls -l somefile; rm -rf ~
```

[`quote()`](https://python-all.ru/3.5/library/shlex.html#shlex.quote) позволяет закрыть брешь в безопасности:

```python
>>> 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()`](https://python-all.ru/3.5/library/shlex.html#shlex.split):

```python
>>> 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`](https://python-all.ru/3.5/library/shlex.html#module-shlex) определяет следующий класс:

#### `class shlex.shlex(instream=None, infile=None, posix=False)`

Экземпляр [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) или его подкласса является объектом лексического анализатора. Аргумент инициализации, если он указан, определяет источник символов. Это должен быть файло- или потокоподобный объект с методами [`read()`](https://python-all.ru/3.5/library/io.html#io.TextIOBase.read) и [`readline()`](https://python-all.ru/3.5/library/io.html#io.TextIOBase.readline), либо строка. Если аргумент не задан, ввод берётся из `sys.stdin`. Второй необязательный аргумент – строка имени файла, которая задаёт начальное значение атрибута [`infile`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.infile). Если аргумент *instream* опущен или равен `sys.stdin`, этот второй аргумент по умолчанию принимает значение "stdin". Аргумент *posix* определяет режим работы: когда *posix* не является истинным (по умолчанию), экземпляр [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) работает в режиме совместимости. При работе в режиме POSIX [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) старается максимально точно соблюдать правила синтаксического анализа оболочки POSIX.

> **См. также**
>
> **Модуль [`configparser`](https://python-all.ru/3.5/library/configparser.html#module-configparser)**
>
> Синтаксический анализатор конфигурационных файлов, аналогичных файлам
>
> `.ini`
>
> в Windows.

## 24.3.1. Объекты shlex

Экземпляр [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) имеет следующие методы:

#### `shlex.get_token()`

Возвращает токен. Если токены были помещены в стек с помощью [`push_token()`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.push_token), извлекает токен из стека. В противном случае читает один токен из входного потока. Если при чтении сразу встречается конец файла, возвращается [`eof`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.eof) (пустая строка (`''`) в не-POSIX режиме и `None` в режиме POSIX).

#### `shlex.push_token(str)`

Помещает аргумент в стек токенов.

#### `shlex.read_token()`

Читает сырой токен. Игнорирует стек возврата и не интерпретирует запросы источника. (Обычно это не является полезной точкой входа и документируется здесь только для полноты.)

#### `shlex.sourcehook(filename)`

Когда [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) обнаруживает запрос источника (см. [`source`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.source) ниже), этому методу передаётся следующий токен в качестве аргумента, и ожидается, что он вернёт кортеж, состоящий из имени файла и открытого файлоподобного объекта.

Обычно этот метод сначала удаляет кавычки из аргумента. Если результат – абсолютный путь, или нет активного предыдущего запроса источника, или предыдущий источник был потоком данных (например, `sys.stdin`), результат остаётся без изменений. В противном случае, если результат – относительный путь, к нему добавляется часть пути каталога файла, находящегося непосредственно перед ним в стеке включения источников (такое поведение аналогично тому, как препроцессор C обрабатывает `#include "file.h"`).

Результат этих действий трактуется как имя файла и возвращается в качестве первого компонента кортежа, а к нему применяется [`open()`](https://python-all.ru/3.5/library/functions.html#open) для получения второго компонента. (Примечание: это обратный порядок аргументов при инициализации экземпляра!)

Этот хук предоставляется, чтобы вы могли использовать его для реализации путей поиска по каталогам, добавления расширений файлов и других трюков с пространствами имён. Соответствующего хука «закрытия» нет, но экземпляр shlex вызовет метод [`close()`](https://python-all.ru/3.5/library/io.html#io.IOBase.close) входного потока источника, когда тот вернёт EOF.

Для более явного управления стеком источников используйте методы [`push_source()`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.push_source) и [`pop_source()`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.pop_source).

#### `shlex.push_source(newstream, newfile=None)`

Помещает поток входного источника в стек ввода. Если указан аргумент filename, он будет доступен позже для использования в сообщениях об ошибках. Это тот же метод, который внутренне используется методом [`sourcehook()`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.sourcehook).

#### `shlex.pop_source()`

Извлекает последний помещённый входной источник из стека ввода. Это тот же метод, который используется внутри, когда лексер достигает EOF для помещённого в стек входного потока.

#### `shlex.error_leader(infile=None, lineno=None)`

Этот метод формирует префикс сообщения об ошибке в формате метки ошибок компилятора C в Unix; формат – `'"%s", line %d: '`, где `%s` заменяется на имя текущего исходного файла, а `%d` – на номер текущей строки ввода (необязательные аргументы позволяют переопределить эти значения).

Это удобство предоставляется для того, чтобы побудить пользователей [`shlex`](https://python-all.ru/3.5/library/shlex.html#module-shlex) генерировать сообщения об ошибках в стандартном, анализируемом формате, который понимают Emacs и другие инструменты Unix.

Экземпляры подклассов [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) имеют несколько открытых переменных экземпляра, которые либо управляют лексическим анализом, либо могут использоваться для отладки:

#### `shlex.commenters`

Строка символов, которые распознаются как начало комментария. Все символы от начала комментария до конца строки игнорируются. По умолчанию включает только `'#'`.

#### `shlex.wordchars`

Строка символов, которые будут накапливаться в составные токены. По умолчанию включает все буквы и цифры ASCII и символ подчёркивания.

#### `shlex.whitespace`

Символы, которые считаются пробельными и пропускаются. Пробельные символы разделяют токены. По умолчанию включает пробел, табуляцию, перевод строки и возврат каретки.

#### `shlex.escape`

Символы, которые будут считаться экранирующими. Это используется только в режиме POSIX и по умолчанию включает только `'\'`.

#### `shlex.quotes`

Символы, которые будут считаться строковыми кавычками. Токен накапливается до тех пор, пока не встретится та же самая кавычка (то есть разные типы кавычек защищают друг друга, как в оболочке). По умолчанию включает ASCII одинарные и двойные кавычки.

#### `shlex.escapedquotes`

Символы в [`quotes`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.quotes), которые будут интерпретировать экранирующие символы, определённые в [`escape`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.escape). Это используется только в режиме POSIX и по умолчанию включает только `'"'`.

#### `shlex.whitespace_split`

Если `True`, токены будут разделяться только по пробельным символам. Это полезно, например, для разбора командных строк с помощью [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex), получая токены аналогично аргументам оболочки.

#### `shlex.infile`

Имя текущего входного файла, установленное при создании экземпляра класса или помещённое в стек последующими запросами источников. Может быть полезно просмотреть его при формировании сообщений об ошибках.

#### `shlex.instream`

Входной поток, из которого данный экземпляр [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) читает символы.

#### `shlex.source`

По умолчанию этот атрибут равен `None`. Если присвоить ему строку, эта строка будет распознаваться как запрос включения на лексическом уровне, аналогично ключевому слову `source` в различных оболочках. То есть следующий непосредственно токен будет открыт как имя файла, и ввод будет поступать из этого потока до достижения конца файла; после этого будет вызван метод [`close()`](https://python-all.ru/3.5/library/io.html#io.IOBase.close) этого потока, и источником ввода снова станет исходный входной поток. Запросы источника могут быть вложенными на любое количество уровней.

#### `shlex.debug`

Если этот атрибут является числовым и равен `1` или больше, экземпляр [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) будет выводить подробную информацию о своих действиях. Если потребуется этим воспользоваться, можно изучить исходный код модуля, чтобы узнать подробности.

#### `shlex.lineno`

Номер строки в исходном файле (количество встреченных символов новой строки плюс один).

#### `shlex.token`

Буфер токенов. Его может быть полезно проверить при перехвате исключений.

#### `shlex.eof`

Токен, используемый для определения конца файла. В не-POSIX-режиме он устанавливается в пустую строку (`''`), а в POSIX-режиме – в `None`.

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

При работе в не-POSIX режиме [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) будет следовать следующим правилам.

- Символы кавычек не распознаются внутри слов (`Do"Not"Separate` разбирается как одно слово `Do"Not"Separate`);
- Символы экранирования не распознаются;
- Заключение символов в кавычки сохраняет буквальное значение всех символов внутри кавычек;
- Закрывающие кавычки разделяют слова (`"Do"Separate` разбирается как `"Do"` и `Separate`);
- Если значение [`whitespace_split`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.whitespace_split) равно `False`, любой символ, не объявленный как символ слова, пробел или кавычка, будет возвращён как односимвольный токен. Если оно равно `True`, [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) будет разделять слова только по пробельным символам;
- EOF обозначается пустой строкой (`''`);
- Невозможно разобрать пустые строки, даже если они в кавычках.

При работе в POSIX режиме [`shlex`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex) будет следовать следующим правилам разбора.

- Кавычки удаляются и не разделяют слова (`"Do"Not"Separate"` разбирается как одно слово `DoNotSeparate`);
- Неэкранированные (не в кавычках) escape-символы (например, `'\'`) сохраняют буквальное значение следующего за ними символа;
- Заключение символов в кавычки, не входящие в [`escapedquotes`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.escapedquotes) (например, `"'"`), сохраняет буквальное значение всех символов внутри кавычек;
- Заключение символов в кавычки, которые являются частью [`escapedquotes`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.escapedquotes) (например, `'"'`), сохраняет буквальное значение всех символов внутри кавычек, за исключением символов, упомянутых в [`escape`](https://python-all.ru/3.5/library/shlex.html#shlex.shlex.escape). Escape-символы сохраняют своё особое значение только в том случае, если за ними следует используемая кавычка или сам escape-символ. В противном случае escape-символ считается обычным символом.
- EOF обозначается значением [`None`](https://python-all.ru/3.5/library/constants.html#None);
- Пустые строки в кавычках (`''`) допускаются.
