Гид по технологиям

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

6 min read CLI инструменты Обновлено 22 Sep 2025
Автодополнение для Bash и Zsh
Автодополнение для Bash и Zsh

Окно терминала с man-страницей почтового клиента Mutt в Linux

Автодополнение делает командную строку удобнее и ускоряет работу. В этой статье объясняется, как добавить автодополнение аргументов к собственным скриптам для 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 [options]”, нужно прочитать первое слово и подбирать варианты дальше:

_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

  1. Поместите completion.sh в репозиторий проекта.
  2. В инструкции добавьте: source /path/to/completion.sh
  3. Для Linux-пакета скопируйте файл в /etc/bashcompletion.d/ и для Zsh в /usr/share/zsh/site-functions/ с именем <команда>.
  4. Запустите тесты: прогоните сценарии автодополнения в интерактивной оболочке.
  5. На 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 командной строки.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

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

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

Остановить фоновые приложения Android и сэкономить батарею
Мобильные устройства

Остановить фоновые приложения Android и сэкономить батарею

Уменьшение degraded RAID1 и LVM на /dev/md1
Linux

Уменьшение degraded RAID1 и LVM на /dev/md1

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

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

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

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

Автодополнение для Bash и Zsh
CLI инструменты

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