介绍
在写命令行程序(工具、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变量上。
示例:var newflag int flag.IntVar(&newflag, "flagname", 1234, "help message for flagname")
- 自定义flag
flag.Var(&flagvar, name, usage)
这种方法要实现flag.Value接口:
示例: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 的定义方式:
可见,默认的 FlagSet 实例在解析出错时会退出程序。由于 FlagSet 中的字段没有 export,其他方式获得 FlagSet实例后,比如:FlagSet{} 或 new(FlagSet),应该调用Init() 方法,以初始化 name 和 errorHandling,否则 name 为空,errorHandling 为 ContinueOnError。// 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)的源码如下:
真正解析参数的方法是非导出方法 parseOne。其解析停止的条件如下: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 }
(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长度(即被设置了的参数个数)。
参考链接
https://www.cnblogs.com/landv/p/11114508.html