Go Cobra CLI 作成チュートリアル
前置き
- 自分の理解用
- 公式のユーザーガイドをベースに生成AI(LLM: Gemini-2.5-Pro)に下書きを出力させ、それをベースに自分なりに記述
- Run関数内の記述はここでは触れない
概要
Go言語で本格的なコマンドラインインターフェース(CLI)ツールを開発する際、多くのプロジェクトで採用されているのが「Cobra」。Cobraは、コマンド、フラグ、引数を柔軟に扱うための豊富な機能を提供し、開発者を力強くサポートする。
この記事では、CobraのインストールからCLIツールを作成するまでの流れを書くものとする。
Cobraとは
Cobraは、Go言語でモダンなCLIアプリケーションを構築するためのライブラリ。一般的に、Cobraを利用するアプリケーションは以下のようなディレクトリ構造になる。
▾ appName/
▾ cmd/
add.go
your.go
commands.go
here.go
main.go
main.goファイルは非常にシンプルで、その唯一の目的はCobraを初期化すること。
package main
import "{pathToYourApp}/cmd"
func main() {
cmd.Execute()
}
Cobraを導入し、簡単なCLIツールを作成するまでの流れを見ていく。公式ではcobra-cliというジェネレータツールの利用が最も簡単な方法として推奨されている。
1. 導入とプロジェクトの初期化
cobra-cliツールをインストールした後、プロジェクトを初期化する。これにより、main.goとルートコマンドを定義するcmd/root.goが生成される。
Cobraライブラリのインストール
go getコマンドで最新版のライブラリをインストールする。
go get -u github.com/spf13/cobra@latest
Cobraプロジェクトの初期化
-
initで初期化する。 -
cobra-cliが無いと怒られたら次の「cobra-cliのインストール」に移る。
cobra-cli init {appName}
例:cobra-cli init app
cobra-cliのインストール
Cobraには、アプリケーションの雛形やコマンドファイルを生成するためのcobra-cliというプログラムが用意されている。これを使うのが、Cobraを導入する最も簡単な方法。
go install github.com/spf13/cobra-cli@latest
Windowsを利用している場合、PATHを通す必要がある(勘違いでインストール後すぐ利用できたらすみません)
C:\Users\{ユーザー名}\go\binのディレクトリにcobra-cli.exeがあるので、このパスを環境変数として設定する。設定方法は割愛する。
2. 実行テスト
main.goの実行
main.goをビルドして実行し、結果が返ってくること。
-
{appName}ディレクトリに移動する go run ./main.go
CLIツールの説明を変更する
root.goファイルを開くと、以下の内容があることが分かる(Use: "hugo"は別の値かも)
var rootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at https://gohugo.io/documentation/`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
}
これを変更し、以下とする。
var rootCmd = &cobra.Command{
Use: "{appName}",
Short: "チュートリアル",
Long: `Cobraを使ったお試しCLIツール`,
}
main.goをビルドして実行し、結果が返ってくること。
go run ./main.go
結果
Cobraを使ったお試しCLIツール
Usage:
app [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
random A brief description of your command
Flags:
-h, --help help for app
-t, --toggle Help message for toggle
Use "app [command] --help" for more information about a command.
実行ファイルの作成
- 実行ファイルを作成することができる
- Windowsの場合は拡張子として
.exeを{appName}の末尾につける
go build -o {appName}.exe ./main.go
# 例
go build -o app.exe ./main.go
実行ファイル{appName}.exeを起動すると結果が返ってくる
.\app.exe
結果
Cobraを使ったお試しCLIツール
Usage:
app [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
random A brief description of your command
Flags:
-h, --help help for app
-t, --toggle Help message for toggle
Use "app [command] --help" for more information about a command.
3. サブコマンドを作成する
公式のユーザーガイドには以下のように言及されています
(画像は翻訳させたやつです)

イメージとしては、機能をフォルダ分けするような感じ。
何をしたいのか分かりやすくなるし、拡張性が向上するので開発がしやすくなるとのこと。
サブコマンド用のファイルを作成する
ここでは、cmdディレクトリ直下に作成する。root.goファイルを同じ階層。
-
{appName}ディレクトリに移動する -
cobra-cli add randomを実行する
基本構造
cobra.Command構造体を使ってコマンドの振る舞いを設定する。
面倒なのでここではShortとLongの記述はデフォルトとする。
var randomCmd = &cobra.Command{
Use: "random",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
// ここにコマンド実行時の処理を記述
},
-
Use: コマンド名 -
Short: ヘルプなどで表示される短い説明文 -
Long: --helpが実行されたときに表示される詳細な説明文 -
Run: コマンドが実行されたときに呼び出される関数で、メインの処理はここに記述する
フラグの定義
コマンドの動作を修飾する。変数を定義し、そこにフラグの値を割り当てるのが一般的な使い方。
細かい使い方はユーザーガイドに記載されてる。
- ローカルフラグ、永続フラグ
- 必須フラグ...etc
init()関数内
フラグをinit()関数内で定義する。
func init() {
rootCmd.AddCommand(randomCmd)
randomCmd.Flags().IntVarP(&images, "images", "i", 1, "取得する画像の数を指定する")
}
rootCmd.AddCommand(randomCmd)
- サブコマンド用のファイルをコマンドで作成した際に、自動で追記される。
Flags().IntVarP()
-
int型の値を受け取るフラグを定義する -
Pがつく関数は短縮形(-i)を同時に設定できる -
IntVarP()のことをcobra特有の書き方だと思ってユーザーガイドやらGithubリポジトリ上を探して「見つからんな~~~」ってやってたけど、ここにあった・・
(&images, "images", "i", 1, "取得する画像の数を指定する")
-
imagesというグローバル変数に、ユーザーが指定したフラグの値が自動的に格納される -
1はユーザーがフラグを指定しなかった際のデフォルトの値 -
go run main.go ramdom -i 5でいうところの-i 5がいわゆるフラグの値
パッケージのドキュメントを元に処理内容をイメージしたメモ
-
func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string)-
p *int: フラグの値を格納するint型のポインタ -
name string: フラグの正式名(Long)。--imagesのように使う -
shorthand string: フラグの短縮名(Short)。-iのように使う -
value int: ユーザーがフラグを指定しなかった場合のデフォルト値 -
usage string:--helpを実行したときに表示されるこのフラグの説明文
-
サブコマンドを指定して実行
go runがすべて成功することを確認する。
※Run関数内の記述や型宣言はここでは触れません。最下部にあるコードを参照。
-
{appName}ディレクトリに移動する go run ./main.go random --images 3go run ./main.go random -i 3go run ./main.go random
まとめ
- Cobraを使うことで簡単にCLIツールを作成することができる
- コマンドやフラグの定義などフレームワークに任せることができる
補足: サブコマンド用のファイルの全文
// app/cmd/random.go
/*
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
*/
package cmd
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/spf13/cobra"
)
type Data struct {
Message string `json:"message"`
Status string `json:"status"`
}
var images int
// randomCmd represents the random command
var randomCmd = &cobra.Command{
Use: "random",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
client := http.Client{
Timeout: 30 * time.Second,
}
for i := range make([]struct{}, images) {
url := "https://dog.ceo/api/breeds/image/random"
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
if err != nil {
fmt.Printf("リクエスト%d回目", i)
fmt.Printf("リクエストの作成に失敗しました: %v", err)
}
req.Header.Add("X-My-Client", "Go-Learn")
res, err := client.Do(req)
if err != nil {
fmt.Printf("リクエストの作成に失敗しました: %v", err)
}
if res.StatusCode != http.StatusOK {
fmt.Printf("APIからエラーステータスが返されました: %s", res.Status)
}
fmt.Println(res.Header.Get("Content-Type"))
var data Data
err = json.NewDecoder(res.Body).Decode(&data)
if err != nil {
fmt.Printf("JSONのデコードに失敗しました: %v", err)
}
res.Body.Close()
fmt.Printf("%+v\n", data.Message)
}
},
}
func init() {
rootCmd.AddCommand(randomCmd)
randomCmd.Flags().IntVarP(&images, "images", "i", 1, "取得する画像の数を指定する")
}
Discussion