gcmd 命令行:定义命令与获取参数
Go 服务常需要命令行入口:./app run、./app migrate --force、./app version。GoFrame v2 的 gcmd 组件(github.com/gogf/gf/v2/os/gcmd)统一了参数解析、命令定义与帮助信息,gf 命令行工具本身(如 gf gen dao)就是基于它实现的,这是官方文档给出的学习参照。
基本概念
- 参数(Arg):不带横线前缀的位置参数,如
build main.go中的main.go;选项(Opt):-o=gf.exe、-y、--name=john这类输入,位置可任意。
基础方法获取参数与选项
package main
import (
"fmt"
"github.com/gogf/gf/v2/os/gcmd"
)
func main() {
gcmd.Init("gf", "build", "main.go", "-o=gf.exe", "-y") // 模拟命令行
fmt.Println(gcmd.GetArg(0)) // gf,索引 0 是程序名
fmt.Println(gcmd.GetArg(1)) // build
fmt.Println(gcmd.GetArgAll()) // [gf build main.go]
fmt.Println(gcmd.GetOpt("o")) // gf.exe
fmt.Println(gcmd.GetOpt("d", "defaultV")) // defaultV,不存在时用默认值
}
GetOpt(name) 在选项不存在时返回 nil,判断“是否带数据”用 GetOpt(name) != nil。GetOptWithEnv("gf.debug") 先读命令行选项、读不到再读 GF_DEBUG 环境变量,适合“配置可被命令行覆盖”的场景。
用 Command 对象定义命令
命令多了之后,推荐建模成 gcmd.Command 对象,自动获得层级命令与帮助信息:
var (
Main = &gcmd.Command{
Name: "main",
Brief: "start http server",
Description: "command entry for starting http server",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.Write("hello")
})
s.SetPort(8199)
s.Run()
return
},
}
)
func main() {
Main.Run(gctx.New()) // 执行 ./app -h 可查看自动生成的帮助
}
回调签名固定为 func(ctx context.Context, parser *gcmd.Parser) error。子命令用 Main.AddCommand(httpCmd, grpcCmd) 挂载,父命令存在子命令时通常不再定义 Func,直接执行 ./app 会打印子命令列表与帮助。
结构化参数:像定义接口一样定义命令
选项一多,硬编码索引就难维护。官方提供“对象化命令 + 结构化输入参数”写法,标签支持 name、short、arg、brief、v(复用校验组件)等:
type cMain struct {
g.Meta `name:"main"`
}
type cMainHttpInput struct {
g.Meta `name:"http" brief:"start http server"`
Name string `v:"required" name:"NAME" arg:"true" brief:"server name"`
Port int `v:"required" short:"p" name:"port" brief:"port of http server"`
}
type cMainHttpOutput struct{}
func (c *cMain) Http(ctx context.Context, in cMainHttpInput) (out *cMainHttpOutput, err error) {
// 参数已自动转换类型并完成 v 标签校验,直接使用 in.Name / in.Port
g.Server(in.Name).SetPort(in.Port).Run()
return
}
func main() {
cmd, err := gcmd.NewFromObject(cMain{})
if err != nil {
panic(err)
}
cmd.Run(gctx.New()) // ./app http my-web -p 8199
}
漏传必填参数时会得到 “arguments validation failed for command” 的校验错误并打印堆栈,便于定位。
注意事项
- 结构化入参的字段匹配“不区分大小写、忽略特殊字符”,如
Name可被name/NAME命中。 gf的所有子命令(gf init、gf gen dao、gf build等)都是该命令模型的实例,更多细节参考其源码与官方文档 goframe.org。
小结
先掌握 GetArg/GetOpt 快速解析,再进阶 gcmd.Command 与 gcmd.NewFromObject 结构化定义,命令行代码就能从“字符串硬解析”升级为“声明式、可校验、自动帮助”的工程写法。