Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 17 из 25 ~18 мин +50 XP

Автодополнение: bash, zsh, fish, powershell

Cobra completion — это команда, которую фреймворк добавляет в ваш CLI бесплатно: одна строка в шелле, и автодополнение bash zsh fish powershell подсказывает подкоманды, флаги и алиасы после каждого Tab. Разберём, что именно генерируется, куда положить скрипт для каждого шелла, зачем нужен флаг --no-descriptions и какие грабли ждут в zsh.

Содержание урока · 11 разделов

Пользователь набрал notes, нажал Tab Tab — и увидел список команд вашей утилиты, набрал notes list -- , нажал Tab — увидел флаги. У kubectl, gh и hugo это работает с первого дня, хотя ни одна из команд не пишет скрипты автодополнения руками: их генерирует Cobra. Механика действительно «из коробки» — root-команда получает её автоматически при первом Execute, и пользователю не нужно ничего знать о вашем коде. При этом вокруг есть тонкости, которые легко пропустить: скрипт надо установить в правильное место конкретного шелла, в zsh без compinit дополнение тихо не заработает, а сгенерированный полгода назад скрипт ничего не знает о командах, добавленных вчера. Этот урок закрывает весь конвейер: от генерации до установки и поддержки.

Cobra completion: что появляется из коробки#

Как только root-команда исполнена, Cobra добавляет к ней команду completion с четырьмя подкомандами: bash, zsh, fish и powershell. Каждая печатает в stdout скрипт автодополнения — длинный, но не ваш: в нём функции конкретного шелла, которые при каждом Tab вызывают вашу же утилиту со скрытой командой __complete и списком уже введённых слов. Бинарник в ответ отдаёт варианты — команды, алиасы, флаги, — и шелл показывает их пользователю. Логика completions живёт в программе, а не в скрипте: добавили подкоманду, поменяли флаг — дополнение обновится на следующем запуске, перегенерировать скрипт заново не обязательно. У каждой подкоманды есть флаг --no-descriptions: подавляет пояснения рядом с вариантами, о нём ниже. Команда completion видна в справке наравне с остальными; если она не нужна — CompletionOptions.DisableDefaultCmd убирает её целиком, а HiddenDefaultCmd оставляет рабочей, но прячет из help.

Куда положить скрипт для каждого шелла#

ШеллУстановкаНюанс
bashsource <(notes completion bash) в .bashrc или файл в /etc/bash_completion.dнужен bash-completion для старых версий
zshnotes completion zsh > "${fpath[1]}/_notes" + compinitбез compinit работает молча и не подсказывает
fishnotes completion fish > ~/.config/fish/completions/notes.fishподхватывает файлы из каталога автоматически
powershellnotes completion powershell | Out-String | Invoke-Expression в $PROFILEвыполняется при каждом старте шелла

Bash: установка в .bashrc

GO
# быстрый путь: вычислять скрипт при каждом старте шелла
echo 'source <(notes completion bash)' >> ~/.bashrc

# или сохранить один раз в каталог bash-completion:
notes completion bash > /etc/bash_completion.d/notes

Запись вида source <(...) вычисляет вывод команды как shell-скрипт при каждом запуске терминала — установка в одну строку, но бинарник обязан быть в PATH к моменту старта шелла. Файл в /etc/bash_completion.d подключается сам, если установлен пакет bash-completion; это путь дистрибутивов и пакетных менеджеров.

Установка в .bashrc и oh-my-zsh#

Bash — самый простой случай, его схема из блока выше закрывает 90% пользователей Linux. Zsh капризнее: скрипт должен лежать в каталоге из массива fpath под именем _notes — с подчёркиванием, совпадающим с именем команды, — а загрузчик функций compinit обязан отработать при старте. Если вы ставили oh-my-zsh, compinit вызывается его init-скриптом автоматически, и автодополнение bash zsh сводится к одной команде записи файла; в голом zsh проверьте, что .zshrc содержит autoload -Uz compinit и compinit, иначе дополнение молча не заведётся — шелл не ругается, просто Tab продолжает предлагать файлы каталога. Fish самый дружелюбный: положили файл в каталог completions — всё, перезапуск не обязателен. Powershell отличается тем, что скрипт исполняется в момент загрузки профиля, поэтому имя бинарника снова должно резолвиться в PATH заранее.

Zsh: файл _notes в fpath

GO
# записать скрипт в первый каталог fpath:
notes completion zsh > "${fpath[1]}/_notes"

# затем перечитать конфиг или открыть новый шелл:
exec zsh

Имя файла обязано начинаться с подчёркивания и совпадать с именем команды: _notes — это соглашение zsh-загрузчика функций. Внутри oh-my-zsh compinit уже вызван, больше ничего делать не нужно. Обратите внимание на перезапись: каждая установка перебивает старый файл, поэтому обновлять дополнение — повторить одну команду.

Проверка: notes completion bash

Пользователь набрал notes completion bash в терминале и нажал Enter. Что произойдёт?

Что подсказывается автоматически#

Стоит понимать, за что скрипт отвечает без вашего участия. Подкоманды и их алиасы — да, включая группы и порядок из урока про группы и алиасы. Флаги — да: и локальные, и персистентные, унаследованные с корня, вместе с шорткатами и текстом помощи в описаниях. Значения булевых флагов true и false — тоже. А вот аргументы команд — нет: для них Cobra без ваших функций предложит файлы каталога, как и любой шелл. Поэтому notes show не подскажет имена заметок: для аргументов нужна ValidArgsFunction, тема следующего урока. Третье место, где дополнение умолчит — значения обычных строковых флагов: notes list --format <Tab> не знает, что format бывает json или table, и снова предложит файлы. Всё остальное обновится само при следующем запуске бинаря — перегенерация скрипта нужна только при обновлении самой Cobra.

Программная генерация при сборке#

Печатать скрипт руками — нормальный путь для пользователей. Но у команд, которые распространяются пакетами, есть второй: генерировать дополнение на этапе сборки и класть файлы прямо в пакет — так делает gh и почти всё, что живёт в brew и apt. В Go-коде это те же самые функции, которые стоят за подкомандами: GenBashCompletionV2, GenZshCompletion, GenFishCompletion, GenPowerShellCompletion. Обычно их прячут за служебную команду go generate или собирают отдельным бинарем, потому что в рантайме пользователю это не нужно. Дополнительный плюс генерации при сборке — версия скрипта всегда совпадает с версией бинарника: новая команда, добавленная в релизе, попадёт и в файл дополнения, который уехал в пакет. Как собрать релиз и проставить версии, разбирает урок про сборку и goreleaser.

Скрытая команда gen-completion

GO
var genCompletionCmd = &cobra.Command{
        Use:    "gen-completion",
        Short:  "Печатает скрипт автодополнения для bash",
        Hidden: true,
        RunE: func(cmd *cobra.Command, args []string) error {
                return cmd.Root().GenBashCompletionV2(os.Stdout, true)
        },
}

func init() {
        rootCmd.AddCommand(genCompletionCmd)
}

GenBashCompletionV2 принимает writer и includeDesc: true оставит описания команд в вариантах, false даст то же, что флаг --no-descriptions. Hidden прячет команду из справки — она нужна сборочному скрипту, а не человеку. Для остальных шеллов меняется одна строка: GenZshCompletion, GenFishCompletion, GenPowerShellCompletion с тем же writer.

Что ответит утилита

Прочитайте код и выберите, что он выведет:

rootCmd.CompletionOptions.DisableDefaultCmd = true

// пользователь запускает: notes completion zsh

--no-descriptions и цена описаний#

По умолчанию __complete возвращает варианты вместе с описаниями: notes lis<Tab> подсказывает list с подписью «Показать заметки». Красиво, но не бесплатно: описания едут отдельным полем, и в zsh с сотнями вариантов второй столбец замедляет отрисовку списка и занимает экран. Флаг --no-descriptions на любой подкоманде completion — или DisableDescriptions в CompletionOptions — выключает подписи: останутся только имена. Третий сценарий — приватные утилиты, где описания раскрывают внутренности: путь команд ни к чему чужому глазу. Отдельно держите в голове рассинхрон версий: скрипт, сгенерированный старым бинарем, может не знать новых полей протокола __complete, поэтому правило простое — дополнение устанавливается из той же версии утилиты, которой пользуется человек. Обновили CLI — попросите пользователя перезаписать файл дополнения или обновите его в пакете при сборке.

Проверка: скрытая команда __complete

Зачем в дереве команд есть скрытая команда __complete?

Версии bash и пакет bash-completion#

У bash два поколения скриптов. Новый V2 — тот, что печатает completion bash сегодня: он короче, быстрее и уважает директивы, но рассчитан на bash четвёртой ветки и установленный пакет bash-completion; на CentOS 7 и прочих раритетах его поведение непредсказуемо. Легаси-генератор GenBashCompletion остался для совместимости: скрипт крупнее, описаний не показывает, но работает даже там, куда новый не доезжает. Выбирают так: современные системы — V2, поддержка древних дистрибутивов — легаси. Проверить, что у пользователя, можно по секции bash в справке команды completion — Cobra печатает подсказки по установке с учётом версии генератора. Для fish и powershell таких поколений нет: один скрипт, одна схема установки из таблицы выше.

Спрячьте completion из справки

Впишите поле CompletionOptions и значение, при котором команда работает, но не видна в help.

func init() { rootCmd.CompletionOptions. = rootCmd.Execute() }

Соберите main с настройкой completion

Расставьте: функция main, скрытие completion, вызов Execute с обработкой ошибки и выход.

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Карточки: автодополнение

Термин

completion

нажмите, чтобы перевернуть
Определение

Сгенерированная Cobra команда с подкомандами bash, zsh, fish, powershell; каждая печатает скрипт автодополнения в stdout.

1 / 5

Что дальше#

Скрипт из этого урока подсказывает команды и флаги — но не аргументы: после notes show Tab предложит файлы, а не имена заметок. Это чинит ValidArgsFunction — следующий урок про динамические подсказки из файлов и API. Дополнение — часть «обвязки» CLI наравне с man-страницами: их генерацию разбирает урок про документацию, а упаковку скриптов в релиз — урок про сборку. Обзор курса — на странице Cobra. Практика на закрепление: установите дополнение для своего шелла, скройте completion из справки и проверьте, что Tab подсказывает и подкоманды, и флаги --no-descriptions против обычных.

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

Коротко: что запомнить

  • Cobra добавляет команду completion с подкомандами bash, zsh, fish, powershell — скрипты печатаются в stdout.
  • Сгенерированный скрипт вызывает скрытую команду __complete: логика дополнения живёт в бинарнике, новые команды подхватываются сами.
  • Bash — source <(notes completion bash) в .bashrc; zsh требует файл _notes в fpath и вызов compinit.
  • --no-descriptions выключает подписи у вариантов — быстрее в zsh и уместно для приватных утилит.
  • DisableDefaultCmd удаляет команду целиком, HiddenDefaultCmd прячет из справки, оставляя рабочей.
  • Дополнение ставится из той же версии бинаря: сгенерированный скрипт старой версии не знает новых команд.

Домашнее задание

Установите автодополнение своей утилиты для основного шелла: bash через .bashrc, zsh через файл в fpath, fish через каталог completions. Затем добавьте rootCmd.CompletionOptions.HiddenDefaultCmd и убедитесь, что completion исчез из справки, но работает. Сгенерируйте скрипт с --no-descriptions и сравните вид подсказок до и после.

Личные заметкиПусто
Хранятся только в вашем браузере (Cobra · Автодополнение: bash, zsh, fish, powershell)

Вопросы и ответы по уроку

Как включить автодополнение для утилиты на Cobra?

Cobra генерирует команду completion автоматически: notes completion bash печатает скрипт, который нужно подключить — source <(notes completion bash) в .bashrc, для zsh сохранить в каталог fpath как _notes, для fish в ~/.config/fish/completions/. Логика подсказок живёт в бинарнике, поэтому после установки дополнение знает все команды и флаги.

Почему в zsh автодополнение не работает?

Чаще всего в .zshrc не вызван compinit, каталог со скриптом не попал в fpath или загрузчик держит устаревший кэш ~/.zcompdump. Симптом — Tab предлагает файлы вместо команд и не ругается. Проверьте порядок: сначала fpath, затем compinit; при переименовании команд удалите ~/.zcompdump* и откройте новый шелл.

Что делает флаг --no-descriptions?

Убирает пояснения справа от вариантов: остаётся только имя команды или флага. Полезно в zsh с длинными списками — отрисовка быстрее — и в приватных утилитах, где описания раскрывают внутренности. Тот же эффект глобально даёт rootCmd.CompletionOptions.DisableDescriptions.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Сравните с альтернативами

Практический вопрос после первых уроков: а почему именно эта библиотека? Мы разобрали конкурентов по одним критериям, с кодом одной задачи рядом и персональным подбором под ваши приоритеты.

Следующая ступень учебного пути

Bubble Tea25 уроков~10 чпрактика25 уроков уже доступны

Bubble Tea: TUI-приложения в терминале

Интерактивный курс Bubble Tea — TUI-фреймворка на Go: Elm-архитектура, bubbles, Lip Gloss, мышь и клавиатура. 25 уроков с примерами и итоговым приложением.

  • Понимать Elm-архитектуру: Model, Update, View, Init
  • Обрабатывать клавиатуру и мышь в терминале
  • Писать асинхронные операции через tea.Cmd, Batch и Sequence
  • Использовать bubbles: list, textinput, textarea, table, viewport, progress, spinner