# 准备工作
安装 cobra-cli,会被安装到 %GOPATH%\bin\cobra-cli.exe(默认:C:\Users\你的用户名\go\bin\cobra-cli.exe)
go install github.com/spf13/cobra-cli@latest
初始化工作
mkdir cobra-study
cd cobra-study
go mod init cobra-study
cobra-cli init
可以得到如下内容
PS C:\Users\Bondrewd\Desktop\Project\PAB\code_study\cobra-study> ls
目录: C:\Users\Bondrewd\Desktop\Project\PAB\code_study\cobra-study
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2026/1/29 13:31 cmd
-a---- 2026/1/29 13:31 187 go.mod
-a---- 2026/1/29 13:31 900 go.sum
-a---- 2026/1/29 13:31 0 LICENSE
-a---- 2026/1/29 13:31 122 main.go
# Cobra 程序的三位一体
Cobra 的设计哲学非常直观,它将 CLI 命令抽象为 Commands(命令)、Args(参数) 和 Flags(标志)。
- Commands(命令):动作的本身。例如
app serve中的serve。 - Args(参数) :动作的对象。例如
app copy file.txt中的file.txt。 - Flags(标志) :动作的修饰。例如
app serve --port 8080中的--port。
# 启动链条

cobra-cli启动链条
# 关键模块
# root.go
定义:
var rootCmd = &cobra.Command{
Use : "myapp [name]",
Short: "一个简短的 demo",
Long : `这是一个详细的描述,通常包含多行,用于解释该程序的复杂功能。`,
// 核心执行逻辑
Run : func(cmd *cobra.Command, args []string) {
if len(args) > 0 {
fmt.Printf("你好, %s!\n", args[0])
}
},
}
这是你定义命令的地方。在 Win11 终端运行 .\myapp.exe --help 时,这些字段决定了用户看到的内容。
Use: 语法定义。第一个单词是命令名,后面是参数占位符。Short: 简介。出现在子命令列表的右侧。Long: 详述。当用户专门查看该命令帮助时显示的详细说明。Run: 函数闭包,它的主要职责是:- 承接逻辑:当用户在终端输入命令并按下回车后,Cobra 解析完参数就会跳转到这里执行。
- 访问数据:它可以直接读取解析后的
args(位置参数)以及在init()中绑定的flags变量。 - 触发业务:通常我们会在
Run里面调用其他的函数(如数据库操作、API 请求等)。
字段名
函数签名
适用场景
Run
func(cmd *Command, args []string)
简单逻辑,不需要返回错误。
RunE
func(cmd *Command, args []string) error
最推荐。如果执行出错,返回 error,Cobra 会自动帮你打印错误。
PostRun
func(cmd *Command, args []string)
执行完主逻辑后的收尾工作(如关闭日志文件)。
PreRun
func(cmd *Command, args []string)
执行主逻辑前的准备工作(如检查用户是否登录)。
# init():参数的“预装配”
在 Go 中,init() 函数会在 main() 函数执行之前运行。
func init() {
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
-
为什么要在init()中定义 Flags? Cobra 需要在程序正式跑起来之前,就知道有哪些参数需要解析。如果在
Run里才定义,程序根本不知道--port是合法的。 -
init()执行顺序:
- 变量初始化 :
rootCmd变量被创建。 init()执行:将 Flags 绑定到rootCmd。main()执行:调用Execute()。
- 变量初始化 :
# Execute():连接器
Execute()函数:
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
- 连接
main与cmd:在 Win11 下,入口是main.go。它只有一行代码cmd.Execute()。这行代码会跳转到root.go中,启动 Cobra 的引擎。 - 职责:解析命令行输入的参数、匹配命令、并最终触发对应的 Run 函数。
# Flags 的两种状态
在 init() 中可以定义Flags 的两种状态:
# Persistent Flags(持久标志/全局标志)
- 特性:具有向下传递性。如果定义在
rootCmd上,那么所有的子命令(如serve,config)都可以使用这个标志。 - 适用场景:全局配置,如
--config配置文件路径、--verbose日志级别。
# Local Flags(本地标志)
- 特性:具有独占性。只在定义的当前命令中生效,子命令无法继承。
- 适用场景:特定功能的修饰,如
serve命令特有的--port。
一个例子,假设你的程序叫 myapp,你在 root.go 的 init() 中定义:
func init() {
// 1. Persistent Flag: 即使运行子命令,也能用 --token
rootCmd.PersistentFlags().StringVar(&token, "token", "", "用户验证令牌")
// 2. Local Flag: 只有运行 myapp 本身(不带子命令)时才能用 --mode
rootCmd.Flags().StringVar(&mode, "mode", "fast", "运行模式")
}
# 参数校验 (Args Validation)
Args 是指那些不带横杠的“裸字符串”(如 myapp copy file1 file2 中的两个文件名)。参数校验就是给你的程序加一道“安检”,防止用户乱传参数。
Cobra 提供了多种内置的校验器,直接写在 Command 结构体中:
cobra.NoArgs: 不允许任何参数(只能用 Flags)。cobra.ExactArgs(n): 必须且只能传 n 个参数。cobra.MinimumNArgs(n): 至少传 n 个参数。cobra.MaximumNArgs(n): 至多传 n 个参数。cobra.RangeArgs(min, max): 参数数量必须在范围内。
一个例子,我们要写一个“加法”命令,必须输入且只能输入 2 个数字:
var addCmd = &cobra.Command{
Use: "add [num1] [num2]",
Short: "计算两个数相加",
// 关键点:强制要求 2 个参数
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("结果是: %s + %s\n", args[0], args[1])
},
}
# 简单的例子
# 无子命令
这是你在 root.go 中可以尝试的最简结构,修改成如下下内容:
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var name string // 用于接收 Flag 的变量
var rootCmd = &cobra.Command{
Use: "hello",
Short: "向某人打招呼",
Run: func(cmd *cobra.Command, args []string) {
// 逻辑处理
fmt.Printf("你好 %s, 欢迎来到 Go 世界!\n", name)
},
}
// 供 main.go 调用
func Execute() {
rootCmd.Execute()
}
func init() {
// 定义一个持久标志 --name 或 -n
rootCmd.PersistentFlags().StringVarP(&name, "name", "n", "陌生人", "输入你的名字")
}
- 编译 :
go build -o hello.exe - 运行默认值:
.\hello.exe→ 输出:你好 陌生人… - 使用 Flag :
.\hello.exe --name Bondrewd→ 输出:你好 Bondrewd…
输出示例:
PS C:\Users\Bondrewd\Desktop\Project\PAB\code_study\cobra-study> .\hello.exe -h
向某人打招呼
Usage:
hello [flags]
Flags:
-h, --help help for say
-n, --name string 输入你的名字 (default "陌生人")
# 多个子命令
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"time"
)
// 1. 定义根命令
var rootCmd = &cobra.Command{
Use: "toolbox",
Short: "一个简单的例子",
Long: `这是一个集成了打招呼和计时功能的 Cobra 演示程序。`,
// 根命令通常不写 Run,或者只打印帮助信息
}
// 2. 定义子命令 A:打招呼
var greetCmd = &cobra.Command{
Use: "greet [name]",
Short: "向指定的人发送问候",
// 参数校验:必须提供且只能提供 1 个参数(姓名)
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Hello, %s! 欢迎学习 Cobra。\n", args[0])
},
}
// 3. 定义子命令 B:计时器
var timerCmd = &cobra.Command{
Use: "timer [seconds]",
Short: "简单的倒计时工具",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("倒计时开始: %s 秒\n", args[0])
// 简单的倒计时逻辑(仅作演示)
time.Sleep(1 * time.Second)
fmt.Println("时间到!")
},
}
// 4. 在 init 中组装它们
func init() {
// 将子命令添加到根命令中
rootCmd.AddCommand(greetCmd)
rootCmd.AddCommand(timerCmd)
// 添加一个 Persistent Flag (全局可用)
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "显示详细日志")
}
func Execute() {
rootCmd.Execute()
}
输出示例:
PS C:\Users\Bondrewd\Desktop\Project\PAB\code_study\cobra-study> .\tset-cli.exe
这是一个集成了打招呼和计时功能的 Cobra 演示程序。
Usage:
toolbox [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
greet 向指定的人发送问候
help Help about any command
timer 简单的倒计时工具
Flags:
-h, --help help for toolbox
-v, --verbose 显示详细日志
Use "toolbox [command] --help" for more information about a command.
------------------------------------------------------------
PS C:\Users\Bondrewd\Desktop\Project\PAB\code_study\cobra-study> .\tset-cli.exe timer 5
倒计时开始: 5 秒
时间到!
------------------------------------------------------------
PS C:\Users\Bondrewd\Desktop\Project\PAB\code_study\cobra-study> .\tset-cli.exe greet PAB
Hello, PAB! 欢迎学习 Cobra。