---
title: "Установка Cobra и первый CLI-проект"
description: "Установка Cobra в Go: ставим cobra-cli через go install, инициализируем проект, разбираем main.go, cmd/root.go и go.mod и делаем первый запуск утилиты."
course: "Cobra: CLI-приложения на Go"
url: "https://golangmaster.ru/courses/cobra/lessons/02-ustanovka-cobra/"
published: "2026-09-19"
updated: "2026-09-21"
minutes: 18
---

# Установка Cobra и первый CLI-проект

*Курс «Cobra: CLI-приложения на Go», урок 2 из 25. ~18 минут. Обновлено 21.09.2026. Источник: https://golangmaster.ru/courses/cobra/lessons/02-ustanovka-cobra/*

Установка Cobra занимает пять минут, но у новичков она регулярно спотыкается: в курсе два разных инструмента — библиотека cobra и генератор cobra-cli, а бинарник после go install оказывается в папке, которой нет в PATH. Разберём установку по шагам, сгенерируем первый проект и разберём каждый его файл.

Задача: через полчаса иметь работающую утилиту, которая отвечает на своё имя в терминале. По пути решим три вопроса, на которых обычно застревают. Первый — что именно ставить: поиск по «cobra» выдаёт и библиотеку, и генератор, и это разные вещи. Второй — куда девается бинарник после go install: если папка ~/go/bin не прописана в PATH, шелл честно ответит command not found, и будет прав. Третий — что генератор создал в проекте и что из этого менять, а что не трогать никогда. Установленный Go — единственная предпосылка: всё остальное делается командами из этого урока. Проверьте себя заранее: go version в терминале должен напечатать что-то вроде go1.22.5 linux/amd64. Если не печатает — сначала поставьте Go с официального сайта, остальное не заработает в принципе. И добавим в план ещё один пункт — привычку проверять справку новой утилиты через --help: она станет главным зеркалом того, что вы поменяли в дереве.

### Установка Cobra: библиотека и генератор — две разные вещи

Установка Cobra начинается с разведки, потому что под этим словом продаются два продукта. Библиотека github.com/spf13/cobra — код, который попадёт в ваш исполняемый файл и будет разбирать командную строку при каждом запуске. Генератор cobra-cli — отдельная утилита для вашей машины: она создаёт каркас проекта и заготовки подкоманд, а в собранном бинарнике не остаётся ни строчки. Ставится она одной командой go install github.com/spf13/cobra-cli@latest — и вот здесь важно понять механику. Имя бинарника задаёт последняя часть пути импорта, поэтому утилита в терминале называется cobra-cli: исторически генератор жил внутри репозитория библиотеки под именем cobra, а потом выделился в отдельный проект. go install не «устанавливает программу в систему» по виндовым меркам: он компилирует пакет и кладёт бинарник в $GOBIN, а если тот не задан — в $GOPATH/bin, то есть по умолчанию в ~/go/bin. Сама библиотека cobra при этом не ставится вовсе: она появится в go.mod вашего проекта позже, когда генератор её туда добавит. Разделение странное ровно до первого запуска — потом становится очевидным.

### Ставим cobra-cli и чиним PATH

```go
# ставим генератор каркасов
go install github.com/spf13/cobra-cli@latest

# бинарник должен оказаться здесь
ls ~/go/bin | grep cobra-cli

# если шелл его не находит — добавьте папку в PATH
export PATH=$PATH:$(go env GOPATH)/bin
```

Первая команда компилирует генератор и кладёт бинарник cobra-cli в $GOPATH/bin — по умолчанию ~/go/bin. Вторая проверяет, что файл на месте. Третья добавляет папку в PATH текущей сессии: чтобы работало всегда, допишите export-строку в ~/.bashrc или ~/.zshrc и перезапустите терминал. На Windows путь другой: %USERPROFILE%\go\bin — его добавляют в переменную среды Path через настройки системы. Если задан $GOBIN, бинарник уедет туда, и искать его в ~/go/bin бессмысленно — go env GOBIN расставит вопросы по местам.

### cobra-cli init: первый проект

Генератор работает внутри существующего модуля Go, поэтому порядок такой: папка, go mod init, cobra-cli init. Пропустить второй шаг нельзя — генератор проверяет наличие go.mod и без него падает с ошибкой go.mod file not found, что новичков сбивает с толку: каркас-то ещё не создан, а ругаться начинают уже на модуль. Имя модуля берите осмысленное — оно станет префиксом импортов во всём проекте: github.com/you/tasker означает, что пакет команд будет импортироваться как github.com/you/tasker/cmd. У init есть необязательные флаги: --author вписывает автора в справку, --license добавляет файл лицензии. Я их обычно пропускаю на прототипах и добавляю перед публикацией — менять автора в сгенерированных файлах потом приходится руками, что мелочь, но неприятная.

### Сессия в терминале: от папки до каркаса

```go
mkdir tasker && cd tasker
go mod init github.com/you/tasker
cobra-cli init

# ответ генератора:
# Your Cobra application is ready at
#   /home/you/code/tasker
#
# Please give more information consider changing
# the short description of your app inside the cmd/root.go

go run main.go
```

Создали папку, инициализировали модуль с именем github.com/you/tasker, развернули каркас. Генератор подсказывает, что Short-описание в cmd/root.go стоит заменить на своё, — мы это сделаем через минуту. go run компилирует пакет на лету и запускает: утилита уже живая.

### Что сгенерировано: карта проекта

Загляните в папку — файлов мало, и каждый на своём месте. main.go — точка входа из трёх строк, cmd/root.go — корень дерева команд, go.mod — манифест модуля с зависимостями, go.sum — контрольные суммы скачанных пакетов. Такой расклад не случайность, а конвенция, которая держится во всех Cobra-проектах от pet-репозиториев до kubectl: логика команд живёт в пакете cmd, точка входа остаётся тонкой. Когда подкоманд станет много, каждая получит свой файл в cmd — add.go, list.go, done.go — и дерево будет собираться из них, как из кубиков. Обновите Short и Long в root.go прямо сейчас: эти строки пользователь увидит первым делом в справке, и «A brief description of your application» там смотрится хуже, чем честное описание вашей утилиты. Заодно инициализируйте git-репозиторий в этой же папке: go.mod и go.sum коммитятся, собранный бинарник отправляйте в .gitignore.

### Файлы нового проекта

- main.go — точка входа: вызывает cmd.Execute() и ничего не знает о командах
- cmd/root.go — корневая команда: имя утилиты, описания, флаги уровня всего приложения
- go.mod — манифест модуля: имя модуля, версия Go, зависимость на github.com/spf13/cobra
- go.sum — контрольные суммы зависимостей; в git-репозиторий включать обязательно
- cmd/ — сюда же лягут будущие подкоманды: одна подкоманда — один файл

### main.go: три строки точки входа

```go
package main

import "github.com/you/tasker/cmd"

func main() {
        cmd.Execute()
}
```

Точка входа сводится к вызову cmd.Execute(). Импорт github.com/you/tasker/cmd — это имя модуля из go.mod плюс папка пакета; такой же приём с тонким main вы видели в структуре программы базового курса. Вся логика CLI живёт в cmd, поэтому main.go не разрастается никогда.

### cmd/root.go: сердце приложения

```go
package cmd

import (
        "os"

        "github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
        Use:   "tasker",
        Short: "Менеджер задач в терминале",
        Long: `Tasker — CLI для личных задач.

Пока команда одна — запуск без аргументов печатает справку.
Подкоманды добавим в следующем уроке.`,
}

func Execute() {
        err := rootCmd.Execute()
        if err != nil {
                os.Exit(1)
        }
}

func init() {
        rootCmd.Flags().BoolP("toggle", "t", false, "toggle help message")
}
```

Пакет cmd объявлен отдельным от main — так его импортирует точка входа. rootCmd — корень будущего дерева: Use станет именем исполняемого файла, Long — развёрнутой справкой. Execute оборачивает rootCmd.Execute() и превращает ошибку в код выхода 1 — скрипты вызова скажут вам спасибо. init() регистрирует флаг toggle, оставленный генератором как образец: разберём его в уроке про флаги.

### Первый запуск: go run и сборка бинарника

Два способа запустить — и они отвечают на разные вопросы. go run main.go компилирует на лету и сразу исполняет: удобно на каждой итерации разработки, бинарник при этом не сохраняется. go build собирает настоящий исполняемый файл в текущую папку: ./tasker — и утилиту можно копировать, добавлять в PATH и отдавать другим людям. Проверьте оба, затем вызовите ./tasker --help: вместо заглушки из генератора должна напечататься ваша справка с Long-текстом. Если go build вдруг не находит main.go — вы не в той папке: генератор кладёт файлы в директорию, где лежит go.mod. Тот же вопрос возникает про cmd/root.go: удалять функцию Execute или переименовывать rootCmd не стоит — main импортирует пакет и зовёт cmd.Execute() по этому имени, каркас рассчитан именно на него. И повторю то, о чём будет напоминать каждый библиотечный урок курса: это всё выполняется локально — браузерная песочница сайта не умеет ни os.Args, ни бинарники, поэтому привычки гонять код постранично здесь не сработают. Терминал рядом с редактором — обязательный инструмент этого курса.

### go.mod: зачем генератору файл модуля

go.mod появился не ради Cobra — это механизм модулей Go, где хранится имя модуля, версия языка и список зависимостей с версиями. Генератору он нужен по двум причинам. Первая техническая: без go.mod не компилируется пакет cmd, потому что импорт внутри проекта строится от имени модуля. Вторая практическая: cobra-cli init добавляет в зависимости github.com/spf13/cobra с актуальной версией — вручную вводить go get не требуется. Если хотите глубже понять механику модулей и файл go.mod, в [уроке про пакеты и модули](/courses/go-advanced/lessons/14-pakety-i-moduli/) продвинутого курса она разобрана целиком. Здесь достаточно одного правила: имя модуля, которое вы передали go mod init, должно быть валидным путём импорта, иначе на шаге cobra-cli init получите невнятную ошибку. Версию библиотеки генератор фиксирует свежей стабильной; поднять её позже можно командой go get -u github.com/spf13/cobra — руками править go.mod не нужно.

> **cobra-cli: command not found.** Самая частая ошибка после установки. Бинарник лежит в ~/go/bin, но эта папка не входит в PATH по умолчанию. Проверка: ls ~/go/bin. Лечение: добавить export PATH=$PATH:$(go env GOPATH)/bin в профиль шелла. Вторая по частоте — забытый go mod init перед cobra-cli init: генератор отвечает go.mod file not found.

> **Версия генератора и обновление.** cobra-cli ставится с суффиксом @latest — это фиксация на последний релиз на момент установки. Со временем генератор стоит обновлять той же командой: шаблоны проектов изредка меняются, например вместе с форматом Execute. Уже созданный проект при этом не затрагивается — генератор работает только по созданию.

### Проверка: установка

**Вопрос:** Какой командой ставится генератор каркасов Cobra?

- go get github.com/spf13/cobra
- ✅ go install github.com/spf13/cobra-cli@latest
- apt install cobra-cli
- go mod init cobra-cli

go install компилирует и кладёт бинарник cobra-cli в $GOPATH/bin. go get cobra не нужен заранее — библиотеку в go.mod добавит сам генератор. apt и go mod init из другого опера: первый не имеет отношения к Go-экосистеме, второй создаёт модуль, а не утилиту.

### Проверка: структура проекта

**Вопрос:** Где генератор размещает корневую команду приложения?

- В main.go рядом с func main
- ✅ В файле cmd/root.go, пакет cmd
- В корне проекта, файл root.go
- Нигде: rootCmd объявляется вручную в каждом проекте по-своему

Конвенция генератора: пакет cmd в одноимённой папке, root.go содержит rootCmd и функцию Execute. main.go остаётся тонким — только вызов cmd.Execute(). Подкоманды позже лягут рядом: add.go, list.go и так далее.

### Что напечатает только что сгенерированный проект

```go
var rootCmd = &cobra.Command{
        Use:   "tasker",
        Short: "Менеджер задач в терминале",
        Long: `Tasker — CLI для личных задач.

Подкоманды добавим в следующем уроке.`,
}

func Execute() {
        err := rootCmd.Execute()
        if err != nil {
                os.Exit(1)
        }
}
```

**Что выведет программа?**

- Ничего: у корня нет Run, программа молча завершится
- ✅ Развёрнутую справку: Long-текст и список доступных команд
- Только строку Менеджер задач в терминале
- Панику: Run обязателен у каждой команды

Если у команды нет Run, Cobra считает её «узлом дерева» и печатает help: развёрнутый Long и список подкоманд — пока пустой. Паники не будет, Run не обязателен: у групповых команд его и не должно быть. Short при этом увидим только в справке родителя.

### Восстановите установку с нуля

Впишите путь импорта генератора, имя модуля, команду каркаса и файл точки входа.

```go
go install github.com/spf13/___@latest
go mod init github.com/you/___
cobra-cli ___
go run ___
```

Подсказка: Генератор — cobra-cli; модуль называем tasker; каркас создаёт init; запускаем main.go.

Правильные ответы в пропусках: `cobra-cli`, `tasker`, `init`, `main.go`

### Соберите последовательность первого проекта

Расставьте команды терминала в правильном порядке: от пустой папки до справки собранной утилиты.

Правильный порядок строк:

1. `mkdir tasker && cd tasker`
2. `go mod init github.com/you/tasker`
3. `go install github.com/spf13/cobra-cli@latest`
4. `cobra-cli init`
5. `go build -o tasker .`
6. `./tasker --help`

### Карточки: первый проект

- **cobra-cli** — Генератор каркасов Cobra: init создаёт проект, add — заготовки подкоманд. В собранный бинарник не попадает.
- **go install ...@latest** — Компилирует пакет и кладёт бинарник в $GOBIN или $GOPATH/bin (по умолчанию ~/go/bin).
- **cmd/root.go** — Корень дерева команд: переменная rootCmd, функция Execute, флаги уровня всего приложения.
- **go.mod** — Манифест модуля: имя модуля (префикс импортов), версия Go, зависимости. Без него cobra-cli init не работает.
- **go run vs go build** — run компилирует и сразу исполняет без сохранения бинарника; build создаёт исполняемый файл для распространения.

### Что дальше

Каркас стоит, утилита отвечает на --help — пора наполнять её командами. В третьем уроке построим [дерево команд](/courses/cobra/lessons/03-komandy-podkomandy/): добавим tasker add и tasker list, разберём rootCmd.AddCommand и поля Use, Short, Long, из которых собирается справка. Четвёртый урок научит команды принимать [аргументы](/courses/cobra/lessons/04-argumenty/) и валидировать их количество. Следом займёмся [флагами](/courses/cobra/lessons/05-flogy-localnye/) — тем самым toggle из root.go наконец получит работу. Домашнее задание ниже закрепляет механику установки: она должна стать рефлексом, потому что новые проекты Cobra вы будете создавать ещё не раз.

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

- Установка Cobra — это два разных действия: генератор cobra-cli на машину и библиотека cobra в go.mod проекта.
- go install кладёт бинарник в $GOPATH/bin — папку нужно добавить в PATH, иначе command not found.
- Порядок первого проекта: mkdir, go mod init, cobra-cli init — без go.mod генератор падает.
- Каркас минимален: тонкий main.go, пакет cmd с root.go, go.mod с зависимостью на cobra.
- У корневой команды без Run запуск печатает справку — паники нет, Run нужен только исполняющим командам.
- go run — для итераций, go build — для бинарника, который можно распространять.
- Всё это выполняется локально с установленным Go — песочница сайта Cobra не запускает.

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

Пройдите путь урока с нуля в другой папке: установите cobra-cli, создайте модуль с собственным именем, например github.com/<ваш ник>/deck, и выполните cobra-cli init. Затем замените Short и Long в cmd/root.go на описание вашей будущей утилиты, соберите бинарник go build и вызовите ./deck --help. В конце удалите файл cmd/root.go строку с флагом toggle и убедитесь, что проект всё ещё собирается. Заодно выполните go env GOPATH и сверьте, что в этой папке лежит cobra-cli: привычка проверять окружение перед установкой экономит десять минут на каждом новом проекте.

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

### Нужно ли ставить саму библиотеку cobra через go get перед init?

Нет. Генератор cobra-cli init сам добавляет github.com/spf13/cobra в go.mod проекта. Вручную go get нужен только если вы строите проект без генератора или обновляете версию библиотеки.

### Куда установился бинарник cobra-cli?

В $GOBIN, а если он не задан — в $GOPATH/bin, по умолчанию это ~/go/bin. Если шелл не находит команду, добавьте эту папку в PATH в профиле шелла и перезапустите терминал.

### Можно ли работать с Cobra без генератора?

Да: библиотека не зависит от cobra-cli. Создайте go.mod, папку cmd с rootCmd и Execute руками — генератор лишь экономит минуты и служит справочником канонической структуры, но не обязателен.
