介绍
在写命令行程序(工具、server)时,对命令参数进行解析是常见的需求。各种语言一般都会提供解析命令行参数的方法或库,以方便程序员使用。在 go 标准库中提供了一个包:flag,方便进行命令行解析。
概述
定义flags
- 标准定义
(1)flag.Type(name, defValue, usage)
其中Type为String, Int, Bool等;并返回一个相应类型的指针。
示例:var ip = flag.Int("flagname", 1234, "help message for flagname")
(2)flag.TypeVar(&flagvar, name, defValue, usage)
将flag绑定在flagvar变量上。
示例: - 自定义flag
flag.Var(&flagvar, name, usage)
这种方法要实现flag.Value接口: - 示例:
var newflag int
flag.IntVar(&newflag, "flagname", 1234, "help message for flagname")
type Value interface {
String() string
Set(string) error
}
type percentage float32
func (p *percentage) Set(s string) error {
v, err := strconv.ParseFloat(s, 32)
*p = percentage(v)
return err
}
func (p *percentage) String() string { return fmt.Sprintf("%f", *p) }
var pip percentage
flag.Var(&pop,"pop","popularity")
解析flag
在所有的 flag 定义完成之后,可以通过调用 flag.Parse() 进行解析。
命令行 flag 的语法有如下三种形式:
-flag // 只支持bool类型
-flag=x
-flag x // 只支持非bool类型
其中第三种形式只能用于非 bool 类型的 flag,默认的,提供了 -flag,则对应的值为 true,否则为 flag.Bool/BoolVar 中指定的默认值;如果希望显示设置为 false 则使用 -flag=false。
int 类型可以是十进制、十六进制、八进制甚至是负数;bool 类型可以是1, 0, t, f, true, false, TRUE, FALSE, True, False。Duration 可以接受任何 time.ParseDuration 能解析的类型。
主要类型的方法
flag 包中主要是FlagSet类型。
- 实例化方式
NewFlagSet() 用于实例化 FlagSet。预定义的 FlagSet 实例 CommandLine 的定义方式:
// The default set of command-line flags, parsed from os.Args.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
- 解析参数
从参数列表中解析定义的 flag。方法参数 arguments 不包括命令名,即应该是os.Args[1:]。Parse(arguments []string)的源码如下:
func (f *FlagSet) Parse(arguments []string) error {
f.parsed = true
f.args = arguments
for {
seen, err := f.parseOne()
if seen {
continue
}
if err == nil {
break
}
switch f.errorHandling {
case ContinueOnError:
return err
case ExitOnError:
os.Exit(2)
case PanicOnError:
panic(err)
}
}
return nil
}
- 真正解析参数的方法是非导出方法 parseOne。其解析停止的条件如下:
(1)第一个为non-flag参数
当遇到单独的一个"-“或不是”-"开始时,会停止解析。
s := f.args[0]
if len(s) == 0 || s[0] != '-' || len(s) == 1 {
return false, nil
}
- 示例:
./nginx - -c 或 ./nginx build -c
,这两种情况,-c 都不会被正确解析。像该例子中的"-“或build(以及之后的参数),我们称之为 non-flag 参数。
(2)两个连续的“–”
当遇到连续的两个”-"开始时,解析停止。
if s[1] == '-' {
num_minuses++
if len(s) == 2 { // "--" terminates the flags
f.args = f.args[1:]
return false, nil
}
}
- 其中,
f.args = f.args[1:]
表示每执行成功一次 parseOne,f.args 会少一个。所以,FlagSet 中的 args 最后留下来的就是所有 non-flag 参数。 - 常见方法
Arg(i int) 和 Args() 这两个方法就是获取 non-flag 参数的;NArg()获得 non-flag 的个数;NFlag() 获得 FlagSet 中的actual长度(即被设置了的参数个数)。
参考链接