GO学习笔记 – 命令行解析
2010 年 11 月 20 日

image
本文主题:基于os.Args与flag实现Golang命令行解析。
小慢哥的原创文章,欢迎转载
目录
▪ 一. os.Args
▪ 二. flag
▪ 三. 结合os.Args与flag实现子命令
▪ 附. 参考文档
一. os.Args
os.Args用于获取通过命令行传入的参数
▷ os.Args[0] :程序执行路径
▷ os.Args[1] :第1个参数
▷ os.Args[2] :第2个参数
▷ len(os.Args) :参数数量
示例如下
package main import ( "fmt" "os" ) func main() { fmt.Println("Program:", os.Args[0]) for i, v := range os.Args[1:] { fmt.Printf("Arg[%d]: %v\n", i, v) } }
测试效果
# 编译执行 go build arg.go ./arg foo "hello world" bar # 输出 Program: ./arg Arg[0]: foo Arg[1]: hello world Arg[2]: bar
二. flag
golang内置的flag模块可以实现命令行flag解析。
什么是flag,举例说明(加粗部分就是flag):
▷ wc -l
▷ ./configure –prefix=/usr/local/nginx
示例如下(摘取自gobyexample)
package main import ( "flag" "fmt" ) func main() { // flag.String返回的是指针 // word表示参数名,foo表示默认值,a string表示参数释义(在-h或解析异常时候会看到) // flag.Int、flag.Bool与flag.String同理,不再赘述 wordPtr := flag.String("word", "foo", "a string") numbPtr := flag.Int("numb", 42, "an int") boolPtr := flag.Bool("fork", false, "a bool") // flag.StringVar返回的是非指针 var svar string flag.StringVar(&svar, "svar", "bar", "a string var") // 进行flag解析 flag.Parse() fmt.Println("word:", *wordPtr) fmt.Println("numb:", *numbPtr) fmt.Println("fork:", *boolPtr) fmt.Println("svar:", svar) fmt.Println("tail:", flag.Args()) }
测试效果
# 编译 go build flag.go ./flag -word=opt -numb=7 -fork -svar=flag # 输出 word: opt numb: 7 fork: true svar: flag tail: [] ./flag -word=opt # 输出 word: opt numb: 42 fork: false svar: bar tail: [] ./flag -word=opt a1 a2 a3 # 输出 word: opt numb: 42 fork: false svar: bar tail: [a1 a2 a3] ./flag -word=opt a1 a2 a3 -numb=7 # 输出 word: opt numb: 42 fork: false svar: bar tail: [a1 a2 a3 -numb=7] ./flag -h # 输出 Usage of ./flag: -fork a bool -numb int an int (default 42) -svar string a string var (default "bar") -word string a string (default "foo") ./flag -wat # 输出 flag provided but not defined: -wat Usage of ./flag: ...
该例子,在测试时候只使用了“单横线+参数名”,实际有4种方式,效果是相同的
-word opt -word=opt --word opt --word=opt
三. 结合os.Args与flag实现子命令
如果想实现子命令效果,例如:
▷ docker ps –last 10
▷ docker images –help
这需要将os.Args和flag结合使用。基本原理:创建多个flag集合(即*flag.FlagSet),每个flag集合对应不同的os.Args
示例如下(摘取自gobyexample)
package main import ( "flag" "fmt" "os" ) func main() { fooCmd := flag.NewFlagSet("foo", flag.ExitOnError) fooEnable := fooCmd.Bool("enable", false, "enable") fooName := fooCmd.String("name", "", "name") barCmd := flag.NewFlagSet("bar", flag.ExitOnError) barLevel := barCmd.Int("level", 0, "level") if len(os.Args) < 2 { fmt.Println("expected 'foo' or 'bar' subcommands") os.Exit(1) } switch os.Args[1] { case "foo": fooCmd.Parse(os.Args[2:]) fmt.Println("subcommand 'foo'") fmt.Println(" enable:", *fooEnable) fmt.Println(" name:", *fooName) fmt.Println(" tail:", fooCmd.Args()) case "bar": barCmd.Parse(os.Args[2:]) fmt.Println("subcommand 'bar'") fmt.Println(" level:", *barLevel) fmt.Println(" tail:", barCmd.Args()) default: fmt.Println("expected 'foo' or 'bar' subcommands") os.Exit(1) } }
测试效果
# 编译 go build subflag.go ./subflag foo -enable -name=joe a1 a2 # 输出 subcommand 'foo' enable: true name: joe tail: [a1 a2] ./subflag bar -level 8 a1 # 输出 subcommand 'bar' level: 8 tail: [a1] ./subflag bar -enable a1 # 输出 flag provided but not defined: -enable Usage of bar: -level int level
附. 参考文档
# os.Args https://gobyexample.com/command-line-arguments # flag https://gobyexample.com/command-line-flags # 子命令 https://gobyexample.com/command-line-subcommands