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

---

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

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

---

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

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

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

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

> **Примечание**
>
> Поскольку функция [`split()`](https://python-all.ru/3.4/library/shlex.html#shlex.split) создаёт экземпляр [`shlex`](https://python-all.ru/3.4/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.4/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.4/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.4/library/shlex.html#module-shlex) определяет следующий класс:

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

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

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

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

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

#### `shlex.get_token()`

Возвращает токен. Если токены были помещены в стек с помощью [`push_token()`](https://python-all.ru/3.4/library/shlex.html#shlex.shlex.push_token), извлекает токен из стека. В противном случае читает один токен из входного потока. Если при чтении сразу встречается конец файла, возвращается [`eof`](https://python-all.ru/3.4/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.4/library/shlex.html#shlex.shlex) обнаруживает запрос исходного файла (см. [`source`](https://python-all.ru/3.4/library/shlex.html#shlex.shlex.source) ниже), этому методу передаётся следующий токен в качестве аргумента, и ожидается, что он вернёт кортеж, состоящий из имени файла и открытого файлоподобного объекта.

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

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

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

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

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

Помещает входной поток-источник в стек ввода. Если указан аргумент имени файла, он будет доступен для использования в сообщениях об ошибках. Это тот же метод, который используется внутри метода [`sourcehook()`](https://python-all.ru/3.4/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.4/library/shlex.html#module-shlex) генерировать сообщения об ошибках в стандартном, анализируемом формате, понятном Emacs и другим инструментам Unix.

Экземпляры подклассов [`shlex`](https://python-all.ru/3.4/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.4/library/shlex.html#shlex.shlex.quotes), которые будут интерпретировать escape-символы, определённые в [`escape`](https://python-all.ru/3.4/library/shlex.html#shlex.shlex.escape). Это используется только в режиме POSIX и по умолчанию включает только `'"'`.

#### `shlex.whitespace_split`

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

#### `shlex.infile`

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

#### `shlex.instream`

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

#### `shlex.source`

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

#### `shlex.debug`

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

#### `shlex.lineno`

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

#### `shlex.token`

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

#### `shlex.eof`

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

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

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

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

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

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