CLI: запуск, dot-команды, in-memory против persistent файла, friendly CLI 1.5
CLI — это первый инструмент, к которому тянется рука при работе с DuckDB. Интерактивная командная строка незаменима для разведки данных, быстрых проверок гипотез, экспериментов с SQL-диалектом. Прежде чем писать пайплайны на Python, инженер обычно открывает CLI и щупает данные руками.
Версия 1.5 серьёзно обновила CLI — теперь его называют «friendly CLI»: цветовые схемы, динамическое приглашение, постраничный вывод, оператор последнего результата. Мы разберём и базовые механики, и эти новшества.
В этом уроке: как запускать CLI и управлять им через dot-команды, в чём разница in-memory и persistent режимов на практике, и что нового в friendly CLI 1.5. Версия, на которую опираемся — DuckDB 1.5.2.
Запуск и два режима базы
Запуск CLI без аргументов открывает транзиентную in-memory базу:
duckdb
v1.5.2 8e52ec4395
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
D
Приглашение D ждёт ввода. Сообщение прямо говорит: база транзиентная, in-memory. Всё, что вы здесь создадите, живёт в оперативной памяти и исчезнет при выходе.
Запуск с именем файла открывает persistent-базу в single-file формате:
duckdb analytics.duckdb
Теперь Connected to a transient in-memory database сменится на путь к файлу. Данные пишутся на диск и переживают перезапуск процесса.
Внутри уже запущенной in-memory сессии можно переключиться на файл командой .open:
D .open analytics.duckdb
После этого активной становится persistent-база. .open без аргумента возвращает к транзиентной in-memory базе.
С .open связана важная тонкость. Когда вы выполняете .open другого файла, CLI закрывает текущую базу и открывает новую — активной становится ровно одна база, заданная последним .open. Это не то же самое, что ATTACH, который подключает дополнительную базу, не закрывая остальные (про ATTACH будет отдельный урок). То есть .open — это «переключиться на эту базу», а ATTACH — «добавить ещё одну базу к сессии». Различать их важно: если вы хотели работать с двумя файлами сразу, .open второго файла не добавит его к первому, а заменит первый. Для одновременной работы с несколькими файлами нужен ATTACH.
Ещё одно следствие: при переключении через .open на новую базу всё, что было в прежней транзиентной in-memory базе, теряется — ведь in-memory база не имеет файла на диске. Поэтому если вы наработали что-то в in-memory режиме и хотите это сохранить, переключение через .open не «перенесёт» данные — их нужно сначала записать (например, через COPY или CREATE TABLE в persistent-базе).
Для разведки незнакомых данных удобен такой приём: запускайте CLI в in-memory режиме (просто duckdb) и читайте внешние файлы напрямую запросами вида SELECT * FROM 'data.parquet'. Persistent-файл здесь не нужен — вы ничего не сохраняете, только смотрите. Persistent-режим включайте, когда хотите создать собственные таблицы и сохранить их.
Dot-команды: управление, а не SQL
В CLI есть два рода ввода. Обычные SQL-операторы заканчиваются точкой с запятой и исполняются движком. И dot-команды — строки, начинающиеся с точки: это мета-команды самого CLI, не SQL. Они не идут в движок и точкой с запятой не заканчиваются.
Dot-команды управляют поведением CLI: подключением, форматом вывода, импортом-экспортом, настройками сессии. Вот основные.
.help — список всех dot-команд с описанием. Первая команда, которую стоит выполнить.
.tables — список таблиц текущей базы. (В friendly CLI 1.5 это стало полноценной dot-командой.)
.schema — показать DDL (определения) объектов базы: как именно созданы таблицы.
.open FILENAME — переключить активную базу на файл; без аргумента — на in-memory.
.mode MODE — формат вывода результатов: duckbox (рамки, по умолчанию), csv, json, markdown, line и другие.
.maxrows N — сколько строк результата печатать, прежде чем вывод усекается.
.timer on — показывать время выполнения каждого запроса.
.read FILENAME — выполнить SQL-скрипт из файла.
.columns — управляет тем, выводить ли результат по колонкам; вместе с .mode влияет на форму вывода.
.quit (или .exit) — выйти из CLI.
Это не полный список — .help показывает все доступные dot-команды, и их заметно больше. Но перечисленные покрывают подавляющее большинство ежедневной работы. Стоит выделить логические группы, на которые dot-команды делятся. Команды подключения (.open) определяют, с какой базой вы работаете. Команды просмотра схемы (.tables, .schema) отвечают на вопрос «что вообще есть в этой базе» — с них обычно начинают разведку незнакомых данных. Команды формата вывода (.mode, .maxrows, .columns) настраивают, как результат показывается. Команды диагностики (.timer) дают обратную связь о выполнении. Команды скриптинга (.read) позволяют исполнять заранее заготовленный SQL. Видя эту структуру, вы понимаете не отдельные команды, а зоны, которыми dot-команды управляют — и легко найдёте нужную в .help.
Небольшая сессия, показывающая dot-команды в работе:
D CREATE TABLE t AS SELECT * FROM range(5) AS r(n);
D .tables
t
D .timer on
D SELECT sum(n) AS total FROM t;
┌───────┐
│ total │
│ int128│
├───────┤
│ 10 │
└───────┘
Run Time (s): real 0.001 user 0.000 sys 0.000
D .mode csv
D SELECT * FROM t LIMIT 3;
n
0
1
2
D .quit
Обратите внимание: .timer on добавил строку времени, .mode csv сменил рамки на CSV. Эти команды меняют CLI, но не данные и не движок.
Полезно понимать, почему dot-команды устроены как отдельный род ввода, а не как SQL. CLI — это программа, у которой есть две зоны ответственности. Одна — собственно общение с движком DuckDB: принять SQL, отдать его движку, показать результат. Вторая — поведение самого CLI как инструмента: к какому файлу подключиться, в каком формате печатать, вести ли таймер, откуда читать скрипт. Вторая зона к движку отношения не имеет — это настройки терминальной программы. Смешивать их в одном синтаксисе было бы неудобно и опасно: команда «сменить формат вывода» не должна выглядеть как SQL и проходить через парсер запросов. Поэтому CLI отделяет мета-команды префиксом-точкой. Это соглашение DuckDB унаследовал от CLI SQLite, где dot-команды устроены так же — ещё одно проявление того, что DuckDB перенял у SQLite модель встраиваемой СУБД с простым CLI.
Из этого следует практическое правило: если строка не заканчивается точкой с запятой и начинается с точки — она вообще не доходит до движка, и спрашивать «почему мой SQL так себя ведёт» бессмысленно. И наоборот: настройки, заданные dot-командами (.mode, .timer, .maxrows), действуют до конца сессии или до следующей такой же команды — они не сбрасываются после каждого запроса.
Формат вывода: .mode под задачу
.mode стоит выделить отдельно — он часто экономит время. Формат вывода выбирают под то, что вы собираетесь делать с результатом.
| Режим | Когда применять |
|---|---|
duckbox | По умолчанию: читать результат глазами, рамки и выравнивание |
csv | Скопировать результат в файл или другую программу |
json | Передать результат в инструмент, ожидающий JSON |
markdown | Вставить таблицу результата в документацию или тикет |
line | Очень широкие строки: каждое поле на своей строке |
line особенно полезен, когда у таблицы много колонок и duckbox не помещается по ширине терминала:
D .mode line
D SELECT 1 AS id, 'DuckDB' AS name, true AS active;
id = 1
name = DuckDB
active = true
Каждое поле — на отдельной строке, ничего не обрезается по ширине.
Режим csv стоит выделить отдельно. Он удобен не только для просмотра — он превращает CLI в инструмент экспорта. Переключившись в .mode csv и направив вывод в файл, можно быстро выгрузить результат запроса как CSV без отдельного оператора COPY. Для разовых выгрузок это короче. Похожим образом .mode markdown экономит время, когда результат запроса нужно вставить в тикет, в pull request или в документацию: таблица сразу в готовом markdown-синтаксисе, не нужно переформатировать вручную. То есть .mode — это не косметика, а способ согласовать вывод CLI с тем, что вы будете делать с результатом дальше: смотреть глазами, скопировать в программу, вставить в текст.
Импорт и скрипты: .read и автоматизация
CLI полезен не только для интерактивной работы — через него можно исполнять заранее подготовленные SQL-скрипты. Команда .read выполняет SQL из файла:
D .read setup.sql
Файл setup.sql может содержать любую последовательность операторов — создание таблиц, загрузку данных, настройку. Это удобно, когда одну и ту же подготовку окружения нужно повторять: вместо того чтобы вводить операторы руками, вы держите их в файле и запускаете одной командой.
CLI можно вызывать и неинтерактивно — передав SQL прямо при запуске. Это превращает DuckDB в инструмент, встраиваемый в shell-скрипты и автоматизацию: запустили duckdb с готовым запросом, получили результат в выбранном формате, использовали его дальше в пайплайне командной строки. Сочетание .mode csv и неинтерактивного вызова делает CLI удобным звеном между DuckDB и обычными утилитами Unix.
CLI занимает в работе своё место: он незаменим для разведки данных, быстрых проверок и подготовки окружения через скрипты. Но основной программный интерфейс для пайплайнов — это Python-клиент, которому посвящён следующий урок. Граница простая: руками и интерактивно — CLI; в коде пайплайна — Python. За обоими, напомним, один и тот же движок.
Friendly CLI 1.5: что нового
Версия 1.5 принесла набор улучшений CLI, ради которых его и называют «friendly». Разберём ключевые.
Оператор _ — последний результат. Подчёркивание ссылается на результат предыдущего запроса. Это удобно для пошагового исследования: посчитали что-то, затем продолжаете от полученного, не оборачивая всё в подзапросы.
D SELECT n FROM range(100) AS r(n) WHERE n % 7 = 0;
D SELECT count(*) AS kratnye_7 FROM _;
┌────────────┐
│ kratnye_7 │
│ int64 │
├────────────┤
│ 15 │
└────────────┘
Второй запрос обратился к _ — результату первого. Не пришлось ни сохранять его во временную таблицу, ни писать вложенный запрос. Это меняет сам стиль интерактивной разведки. Без _ исследование данных «вглубь» означает либо растущую матрёшку подзапросов, либо череду временных таблиц, которые потом надо помнить и убирать. С _ каждый шаг — отдельный читаемый запрос, а _ склеивает шаги. Вы фактически ведёте диалог с данными: задали вопрос, увидели ответ, задали следующий вопрос про этот ответ.
Цветовые схемы. CLI поддерживает цветовое оформление вывода — это улучшает читаемость, особенно крупных результатов.
Динамическое приглашение. Приглашение может отражать состояние сессии — например, к какой базе вы подключены, — а не быть статичным D.
Постраничный вывод (pager). Большой результат CLI может показывать постранично, как less, вместо того чтобы прокрутить весь вывод за один раз. Длинные результаты так гораздо удобнее листать.
За CLI и за Python-клиентом стоит один и тот же движок DuckDB. Friendly CLI 1.5 улучшает удобство интерактивной работы — приглашение, цвета, pager, оператор _ — но не меняет ни оптимизатор, ни исполнитель. Производительность одного и того же запроса в CLI и в Python одинакова; friendly CLI делает приятнее именно ручную работу с движком.
Попробуй сам
Освойте CLI на практике, пройдя короткую сессию.
- Запустите CLI без аргументов. Прочитайте стартовое сообщение и убедитесь, что база транзиентная in-memory. Выполните
.helpи пролистайте список dot-команд. - Создайте таблицу:
CREATE TABLE nums AS SELECT * FROM range(20) AS r(n);. Проверьте её через.tablesи.schema. - Включите
.timer onи выполните агрегацию:SELECT sum(n), avg(n) FROM nums;. Посмотрите на строку времени. - Используйте оператор
_: после запросаSELECT n FROM nums WHERE n > 10;выполнитеSELECT count(*) FROM _;— убедитесь, что_сослался на предыдущий результат. - Переберите форматы:
.mode csv, затем.mode markdown, затем.mode line— каждый раз повторяяSELECT * FROM nums LIMIT 3;. Сравните вывод. - Выйдите через
.quit. Запустите CLI заново — но уже с persistent-файлом:duckdb mydata.duckdb. Создайте в нём таблицу, выйдите, откройте файл снова и через.tablesубедитесь, что таблица пережила перезапуск.
Шаг 6 — главный: он на практике показывает разницу in-memory и persistent режимов.
Trino CLI: dot-команды для распределённого движка