ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

命令行参数解析工具:Pflag 使用介绍

2022-04-04 21:00:06  阅读:379  来源: 互联网

标签:Pflag string Flag flag pflag 命令行 解析 name


​ Go 服务开发中,经常需要给开发的组件加上各种启动参数来配置服务进程,影响服务的行为。像 kube-apiserver 就有多达 200 多个启动参数,而且这些参数的类型各不相同(例如:string、int、ip 类型等),使用方式也不相同(例如:需要支持 -- 长选项,- 短选项等),所以我们需要一个强大的命令行参数解析工具。

​ 虽然 Go 源码中提供了一个标准库 Flag 包,用来对命令行参数进行解析,但在大型项目中应用更广泛的是另外一个包:Pflag。Pflag 提供了很多强大的特性,非常适合用来构建大型项目,一些耳熟能详的开源项目都是用 Pflag 来进行命令行参数解析的,例如:Kubernetes、Istio、Helm、Docker、Etcd 等。

1、Pflag 包 Flag 定义

学习地址:https://github.com/spf13/pflag
Pflag 可以对命令行参数进行处理,一个命令行参数在 Pflag 包中会解析为一个 Flag 类型的变量。Flag 是一个结构体,定义如下:

type Flag struct { 
    Name string // flag长选项的名称 
    Shorthand string // flag短选项的名称,一个缩写的字符 
    Usage string // flag的使用文本 
    Value Value // flag的值 
    DefValue string // flag的默认值 
    Changed bool // 记录flag的值是否有被设置过 
    NoOptDefVal string // 当flag出现在命令行,但是没有指定选项值时的默认值 
    Deprecated string // 记录该flag是否被放弃 
    Hidden bool // 如果值为true,则从help/usage输出信息中隐藏该flag 
    ShorthandDeprecated string // 如果flag的短选项被废弃,当使用flag的短选项时打印该信息 
    Annotations map[string][]string // 给flag设置注解
}

Flag 的值是一个 Value 类型的接口,Value 定义如下:

type Value interface { 
    String() string // 将flag类型的值转换为string类型的值,并返回string的内容 
    Set(string) error // 将string类型的值转换为flag类型的值,转换失败报错 
    Type() string // 返回flag的类型,例如:string、int、ip等
}

通过将 Flag 的值抽象成一个 interface 接口,我们就可以自定义 Flag 的类型了。只要实现了 Value 接口的结构体,就是一个新类型。

2、Pflag 包 FlagSet 定义

Pflag 除了支持单个的 Flag 之外,还支持 FlagSet。FlagSet 是一些预先定义好的 Flag 的集合,几乎所有的 Pflag 操作,都需要借助 FlagSet 提供的方法来完成。在实际开发中,我们可以使用两种方法来获取并使用 FlagSet:

  • 方法一,调用 NewFlagSet 创建一个 FlagSet。
  • 方法二,使用 Pflag 包定义的全局 FlagSet:CommandLine。实际上 CommandLine 也是由 NewFlagSet 函数创建的。

第一种方法,自定义 FlagSet。下面是一个自定义 FlagSet 的示例:

var version bool
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
flagSet.BoolVar(&version, "version", true, "Print version information and quit.")
flagSet.Parse(os.Args[1:])
fmt.Println(version)

第二种方法,使用全局 FlagSet。下面是一个使用全局 FlagSet 的示例:

import "github.com/spf13/pflag"
var version bool
pflag.BoolVarP(&version, "version", "v", true, "Print version information and quit.")

这其中,pflag.BoolVarP 函数定义如下:

func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { 
    flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage)
    flag.NoOptDefVal = "true"
}

可以看到 pflag.BoolVarP 最终调用了 CommandLine,CommandLine 是一个包级别的变量,定义为:

// CommandLine is the default set of command-line flags, parsed from os.Args.var 
CommandLine = NewFlagSet(os.Args[0], ExitOnError)

在一些不需要定义子命令的命令行工具中,我们可以直接使用全局的 FlagSet,更加简单方便。

3 、Pflag 使用方法

​ 上面,我们介绍了使用 Pflag 包的两个核心结构体。接下来,我来详细介绍下 Pflag 的常见使用方法。Pflag 有很多强大的功能,我这里介绍 7 个常见的使用方法。
1、支持多种命令行参数定义方式。

Pflag 支持以下 4 种命令行参数定义方式:

  • 支持长选项、默认值和使用文本,并将标志的值存储在指针中。
var name = pflag.String("name", "colin", "Input Your Name")
  • 支持长选项、短选项、默认值和使用文本,并将标志的值存储在指针中。
var name = pflag.StringP("name", "n", "colin", "Input Your Name")
  • 支持长选项、默认值和使用文本,并将标志的值绑定到变量。
var name string
pflag.StringVar(&name, "name", "colin", "Input Your Name")
  • 支持长选项、短选项、默认值和使用文本,并将标志的值绑定到变量。
var name string
pflag.StringVarP(&name, "name", "n","colin", "Input Your Name")

上面的函数命名是有规则的:

  • 函数名带Var说明是将标志的值绑定到变量,否则是将标志的值存储在指针中。
  • 函数名带P说明支持短选项,否则不支持短选项。

2、使用Get获取参数的值。

​ 可以使用Get来获取标志的值,代表 Pflag 所支持的类型。例如:有一个 pflag.FlagSet,带有一个名为 flagname 的 int 类型的标志,可以使用GetInt()来获取 int 值。需要注意 flagname 必须存在且必须是 int,例如:

i, err := flagset.GetInt("flagname")

3、获取非选项参数。

package main
import ( "fmt" "github.com/spf13/pflag")
var ( 
    flagvar = pflag.Int("flagname", 1234, "help message for flagname")
)
func main() { 
    pflag.Parse() 
    fmt.Printf("argument number is: %v\n", pflag.NArg()) 
    fmt.Printf("argument list is: %v\n", pflag.Args()) 
    fmt.Printf("the first argument is: %v\n", pflag.Arg(0))
}

执行上述代码,输出如下:

go run .\pflag_example2.go --flagname 12345  345 567

argument number is: 2
argument list is: [345 567]
the first argument is: 345

​ 在定义完标志之后,可以调用pflag.Parse()来解析定义的标志。解析后,可通过pflag.Args()返回所有的非选项参数,通过pflag.Arg(i)返回第 i 个非选项参数。参数下标 0 到 pflag.NArg() - 1。

4、指定了选项但是没有指定选项值时的默认值。
​ 创建一个 Flag 后,可以为这个 Flag 设置 pflag.NoOptDefVal。如果一个 Flag 具有 NoOptDefVal,并且该 Flag 在命令行上没有设置这个 Flag 的值,则该标志将设置为 NoOptDefVal 指定的值。例如:

var ip = pflag.IntP("flagname", "f", 1234, "help message")
pflag.Lookup("flagname").NoOptDefVal = "4321"

上面的代码会产生结果如下表:

命令行参数 解析结果
--flagname=1357 ip=1357
--flagname ip=4321
[nothing] ip=1234

5、弃用标志或者标志的简写。

​ Pflag 可以弃用标志或者标志的简写。弃用的标志或标志简写在帮助文本中会被隐藏,并在使用不推荐的标志或简写时打印正确的用法提示。例如,弃用名为 logmode 的标志,并告知用户应该使用哪个标志代替:

// deprecate a flag by specifying its name and a usage message
pflag.CommandLine.MarkDeprecated("logmode", "please use --log-mode instead")

这样隐藏了帮助文本中的 logmode,并且当使用 logmode 时,打印了Flag --logmode has been deprecated, please use --log-mode instead。

6、保留名为 port 的标志,但是弃用它的简写形式。

pflag.IntVarP(&port, "port", "P", 3306, "MySQL service host port.")
// deprecate a flag shorthand by specifying its flag name and a usage message
pflag.CommandLine.MarkShorthandDeprecated("port", "please use --port only")

​ 这样隐藏了帮助文本中的简写 P,并且当使用简写 P 时,打印了Flag shorthand -P has been deprecated, please use --port only。usage message 在此处必不可少,并且不应为空。

7、隐藏标志。

​ 可以将 Flag 标记为隐藏的,这意味着它仍将正常运行,但不会显示在 usage/help 文本中。例如:隐藏名为 secretFlag 的标志,只在内部使用,并且不希望它显示在帮助文本或者使用文本中。代码如下:

// hide a flag by specifying its name
pflag.CommandLine.MarkHidden("secretFlag")

标签:Pflag,string,Flag,flag,pflag,命令行,解析,name
来源: https://www.cnblogs.com/liweiboy/p/16100413.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有