在写命令行程序(工具、server)时,对命令行参数进行解析,是一种常见的需求。各种语言一般都会提供相应的方法或库,以方便开发者使用。在go标准库中提供了一个包:flag,方便进行命令行解析。也就是说,Go的flag包用来解析命令行参数。
一、命令行flag语法形式
命令行flag的语法有如下三种形式:
-flag // 只支持bool类型
-flag=x
-flag x // 只支持非bool类型
其中,第一种形式只能用于bool类型。第三种形式只能用于非bool类型的flag。
第三种形式只能用于非bool类型的原因是:对于这样的命令 cmd -x *,如果有一个文件名字是:0或false等,则命令的原意会改变。因为bool类型支持-flag这种形式,所以go语言在Parse()方法中对bool类型进行了特殊处理。默认的,若提供了-flag,则对应的值为true;否则,则为flag.Bool/BoolVar中指定的默认值;如果希望显示地设置为false,则使用-flag=false。
二、定义flag的方式
定义flags有两种方式:
1)flag.Xxx(),其中Xxx可以是Int、String等;返回一个相应类型的指针,如:
var ip = flag.Int("flagname", 123, "int flag for flagname")
2)flag.XxxVar(),将flag绑定到一个变量上,如:
var flagvar int
flag.IntVar(&flagvar, "flagname", 123, "int flag for flagname")
另外,还可以创建自定义flag,只要实现flag.Value接口即可(要求receiver是指针),这时候可以通过如下方式定义该flag:
flag.Var(&flagVal, "name", "help message for flagname")
例如,解析以英文逗号分割的字符串直接到 slice 中,我们可以定义如下 Value:
type sliceValue []string
func newSliceValue(vals []string, p *[]string) *sliceValue {
*p = vals
return (*sliceValue)(p)
}
func (s *sliceValue) Set(val string) error {
*s = sliceValue(strings.Split(val, ","))
return nil
}
func (s *sliceValue) Get() interface{} { return []string(*s) }
func (s *sliceValue) String() string { return strings.Join([]string(*s), ",") }
之后,可以这么使用:
var languages []string
flag.Var(newSliceValue([]string{}, &languages), "slice", "I like programming `languages`")
这样通过 -slice “go,php” 这样的形式传递参数,languages 得到的就是 [go, php]。flag 包中对 Duration 这种非基本类型的支持,使用的就是类似这样的方式。
三、主要API
我们常用的API如下:
1. 直接获取命令行参数
// 获取名字为name的参数值,默认值为value,用法为usage
// 注意返回值是一个指针
// 类似的方法还有 Int(),Bool()等。
func String(name string, value string, usage string) *string
2. 将获取的命令行参数赋给指定值
// 这种方式p作为返回值,可以传入变量的地址
// 类似的方法还有 IntVar(),BoolVar()等。
func StringVar(p *string, name string, value string, usage string)
3. 展示使用方法
// Usage用来打印用法
var Usage = func() {
// ...
}
4. 解析参数
// 解析参数,应在设置完参数变量后调用
func Parse()
四、使用示例
代码示例:
ackage main
import (
"flag"
"fmt"
// "os"
)
func main() {
// fmt.Println(os.Args)
ok := flag.Bool("ok", false, "is ok")
id := flag.Int("id", 0, "id")
port := flag.String("port", ":8080", "http listen port")
var name string
flag.StringVar(&name, "name", "Jack", "name")
flag.Parse()
// flag.Usage()
others := flag.Args()
fmt.Println("ok:", *ok)
fmt.Println("id:", *id)
fmt.Println("port:", *port)
fmt.Println("name:", name)
fmt.Println("other:", others)
}
执行示例如下:
$ go run flag.go -ok -id 11111 -port 8899 -name TestUser very good
ok: true
id: 11111
port: 8899
name: TestUser
other: [very good]