Автодополнение для Bash и Zsh

Автодополнение делает командную строку удобнее и ускоряет работу. В этой статье объясняется, как добавить автодополнение аргументов к собственным скриптам для Zsh и Bash, показаны простые и переносимые шаблоны, советы по отладке, тесты и чек‑листы для production.
Как работает автодополнение
Autocomplete (автодополнение) существует в Unix-подобных системах давно и поддерживается современными оболочками, такими как Bash и Zsh. В типичном виде автодополнение помогает завершать имена команд и файлов на основе PATH и текущей файловой системы. Но самый мощный вариант — это автодополнение аргументов команды (опции, подкоманды, имена ресурсов).
Автодополнение аргументов полезно для:
- Быстрого обнаружения подкоманд и опций.
- Снижения числа опечаток.
- Улучшения UX командной утилиты без man-страниц.
Важно: авто дополняет именно оболочка, в которой пользователь нажимает Tab. Скрипт должен зарегистрировать обработчик для этой оболочки.
Пример простой команды
Рассмотрим тривиальный скрипт управления списком дел. В статье использован пример на zsh, но логика общая.
#!/usr/bin/env zsh
FILE="$HOME/.local/state/todos/data"
if [ "$#" -eq "1" ] && [ "$1" = "edit" ] ; then
"${EDITOR:-vi}" "$FILE"
elif [ "$#" -eq "1" ] && [ "$1" = "help" ] ; then
echo "Usage: $(basename $0) [ edit | help ]"
else
<"$FILE" grep -v ^~
fi
Если этот скрипт назвать todos и поместить в PATH, доступны команды:
- todos — вывести список
- todos help — показать помощь
- todos edit — открыть в редакторе
Добавление автодополнения поможет быстро обнаруживать подкоманды.
Минимальный скрипт автодополнения для Zsh
Простейший обработчик для Zsh выглядит так:
_complete_todos() {
compadd help edit
}
autoload -Uz compinit
compinit
compdef _complete_todos todos
Объяснение:
- _complete_todos — функция-обработчик, которая вызывает compadd для перечисления вариантов.
- compinit загружает модуль автодополнения Zsh.
- compdef связывает функцию с командой todos.
Вы можете положить этот код в ~/.zshrc или в файл в fpath (имя файла должно начинаться с символа подчёркивания).
Как Bash отличается
Bash требует, чтобы вы сами вычисляли релевантные варианты: он не накладывает дополнительной логики. В простейшем виде для Bash:
_complete_todos_bash() {
COMPREPLY=(help edit)
}
complete -F _complete_todos_bash todos
Проблема: Bash выведет все варианты независимо от уже введённого текста.
Переменные, которые пригодятся при обработке в Bash:
- COMP_WORDS — массив слов командной строки.
- COMP_CWORD — индекс слова, где находится курсор.
Удобная утилита — compgen:
$ compgen -W "one two three" o
one
$ compgen -W "one two three" t
two
three
Поэтому исправленный вариант для контекстного подбора:
_complete_todos_bash() {
COMPREPLY=( $( compgen -W "edit help" -- "${COMP_WORDS[$COMP_CWORD]}" ) )
}
complete -F _complete_todos_bash todos
Универсальный переносимый скрипт (Zsh и Bash)
Ниже полный пример, который работает в обеих оболочках, определяя, в каком окружении он выполняется:
SUBCOMMANDS=(help edit halt)
_complete_todos_zsh() {
compadd $SUBCOMMANDS
}
_complete_todos_bash() {
COMPREPLY=( $( compgen -W "${SUBCOMMANDS[*]}" -- "${COMP_WORDS[$COMP_CWORD]}" ) )
}
if [ -n "${ZSH_VERSION:-}" ]; then
autoload -Uz compinit
compinit
compdef _complete_todos_zsh todos
elif [ -n "${BASH_VERSION:-}" ]; then
complete -F _complete_todos_bash todos
fi
Сохраняйте этот код в completion.sh и подключайте его из ~/.bashrc и/или ~/.zshrc:
. /path/to/completion.sh
Важно: оболочка, в которой регистрируется автодополнение, — та, в которой пользователь нажимает Tab, а не та, в которой выполняется команда.
Когда нужно улучшить этот базовый подход
Базовый статический список хорош для небольших утилит, но для реальных инструментов часто нужно:
- Учитывать уже введённые опции (порядок аргументов).
- Подгружать динамический список (файлы, сервисы, конфиги).
- Поддерживать длинные опции с — и короткие -o.
- Обрабатывать контекст (после – filename, после subcommand ещё опции).
Ниже приведены расширенные примеры и паттерны.
Пример: динамическое автодополнение из файлов
Если ваши варианты зависят от содержимого каталога или от файла состояния, генерируйте список динамически.
Bash-обработчик, который подставляет имена файлов из каталога ~/projects:
_complete_projects() {
local cur
cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=( $( compgen -W "$(ls -1 ~/projects 2>/dev/null)" -- "$cur" ) )
}
complete -F _complete_projects projects
Аналог для Zsh:
_complete_projects_zsh() {
local -a arr
arr=(~+/projects/*(.:t))
compadd -- $arr
}
compdef _complete_projects_zsh projects
Примечание: в Zsh можно использовать глобальные опции маски файлов, а также фаворитный модуль zsh/parameter.
Пример: контекстные подкоманды и опции (Bash)
Если у вас есть структура вроде “tool
_complete_tool() {
local cur prev
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if [[ ${COMP_CWORD} -eq 1 ]]; then
COMPREPLY=( $(compgen -W "start stop status" -- "$cur") )
return
fi
case "${COMP_WORDS[1]}" in
start)
COMPREPLY=( $(compgen -W "--daemon --config= --port=" -- "$cur") )
;;
stop)
COMPREPLY=( $(compgen -W "--force --timeout=" -- "$cur") )
;;
*)
COMPREPLY=()
;;
esac
}
complete -F _complete_tool tool
Этот шаблон обрабатывает разные подкоманды по-разному.
Zsh: использование _arguments для сложных вариантов
Zsh предоставляет высокоуровневую функцию _arguments, позволяющую декларировать опции с метаданными и автогенерировать подсказки:
# Пример в Zsh
_arguments \
'(-h --help)'{-h,--help}'[Показать помощь]' \
'(-v --verbose)'{-v,--verbose}'[Подробный режим]' \
'--config=[Путь к конфигу]:файл:->config' \
'*::параметры:->args'
case $state in
config)
_files
;;
args)
compadd start stop status
;;
esac
_arguments упрощает сложную валидацию опций и их подсказок.
Отладка и тестирование
Как отлаживать автодополнение:
- Загрузите обработчик в текущую сессию вручную и пробуйте Tab.
- Для Bash добавьте set -x в начале обработчика, чтобы видеть, какие ветки выполняются.
- В Zsh используйте typeset -p COMP_WORDS и echo $words для диагностики.
Критерии приёмки (пример):
- Подстановка подкоманд при пустом аргументе.
- Ограничение подсказок согласно введённым символам.
- Поддержка сочетаний опций (короткие/длинные).
- Отсутствие заметных задержек при генерации подсказок.
Тестовые сценарии:
- todos
показывает список. - todos e
предлагает edit, но не help. - При большом числе динамических вариантов задержка < 0.5 с (оценка вручную).
Чек-лист по ролям
Автор скрипта:
- Добавил автодополнение в репозиторий (completion.sh).
- Документировал инструкции по установке (куда source добавить).
- Обеспечил тесты для основных сценариев.
Системный администратор:
- Развернул файл в /etc/bash_completion.d/ или /usr/share/zsh/site-functions.
- Проверил совместимость версий оболочек.
Пользователь:
- Источник (source) подключён к shellrc.
- Проверил автодополнение для всех основных команд.
Шаблон развертывания и SOP
- Поместите completion.sh в репозиторий проекта.
- В инструкции добавьте: source /path/to/completion.sh
- Для Linux-пакета скопируйте файл в /etc/bashcompletion.d/ и для Zsh в /usr/share/zsh/site-functions/ с именем <команда>.
- Запустите тесты: прогоните сценарии автодополнения в интерактивной оболочке.
- На CI можно эмулировать поведение автодополнения, запуская функции с имитацией переменных окружения.
Потенциальные проблемы и когда автодополнение не сработает
- Скрипт не в PATH или не имеет права на исполнение.
- Файл не подключён (source) в shell конфиге.
- Для Zsh модуль compinit не загружен или раннее определение compdef затеняет новый.
- В Bash обработчик возвращает слишком большой список — это может замедлить оболочку.
- Нестандартные терминалы или SSH‑сессии с ограниченными возможностями клавиш.
Безопасность и конфиденциальность
- Не подставляйте чувствительные данные (пароли, токены) в варианты автодополнения.
- Если динамические варианты читаются из сети или внешних сервисов, кешируйте результаты и контролируйте таймауты.
Ментальные модели и эвристики
- «Минимум — максимум»: начните с простого статического списка, затем расширяйте по необходимости.
- «Слой логики в обработчике»: пусть обработчик будет только преобразованием доступных данных в список вариантов, а не выполняет тяжёлые операции.
- «Не доверяй оболочке»: Bash даст вам полную свободу — вы отвечаете за фильтрацию и контекст.
Сравнение подходов (кратко)
- Zsh _arguments / compadd: высокая абстракция, удобный синтаксис, меньше кода.
- Bash + compgen: низкоуровневый контроль, универсальность, но больше шаблонного кода.
- Универсальный скрипт: проще для поддержки в многопользовательской среде.
Шаблоны и сниппеты
Динамическая генерация подкоманд в Bash из исполняемых файлов в директории bin:
SUBCOMMANDS=( $(ls -1 ~/mycli-plugins 2>/dev/null) )
_complete_mycli() {
COMPREPLY=( $(compgen -W "${SUBCOMMANDS[*]}" -- "${COMP_WORDS[$COMP_CWORD]}") )
}
complete -F _complete_mycli mycli
Zsh: комбинирование статических и динамических вариантов
_complete_combo() {
local -a arr
arr=(help edit)
arr+=(~/.config/extra-commands/*(.t))
compadd -- $arr
}
compdef _complete_combo mycmd
Совместимость и миграция
- Для Debian/Ubuntu: положите bash-скрипт в /etc/bashcompletion.d/ (назовите без подчёркивания), а Zsh‑функцию — в /usr/share/zsh/site-functions/ с именем <имя>.
- Проверяйте совместимость с версиями Bash <4 и Zsh <5 (основные функции поддерживаются, но тонкости могут отличаться).
Таблица ключевых переменных и функций
- Zsh: compadd, compinit, compdef, _arguments
- Bash: complete, COMPREPLY, compgen, COMP_WORDS, COMP_CWORD
Краткий глоссарий
- compadd — функция Zsh для добавления подсказок.
- compgen — утилита Bash для генерации слов по шаблону.
- COMPREPLY — массив Bash, содержащий варианты автодополнения.
- compdef/complete — связывающие механизмы для Zsh и Bash.
Краткий итог
Автодополнение повышает удобство и надёжность CLI‑утилит. Для простых задач достаточно статического списка, но для серьёзных проектов стоит реализовать контекстную и динамическую генерацию вариантов, покрыть тестами и разместить файлы в стандартных системных каталогах для автоматической загрузки.
Важное: не добавляйте секретные данные в подсказки, и кешируйте дорогостоящие операции.
Примените предложенные шаблоны и адаптируйте их под свои сценарии — так вы получите приятный и предсказуемый UX командной строки.
Похожие материалы

Видеообзоры в NotebookLM — как быстро создать

Остановить фоновые приложения Android и сэкономить батарею
Уменьшение degraded RAID1 и LVM на /dev/md1

Instagram Stories без звука на iPhone — как исправить

Отследить поддельный номер: руководство и защита
