我的编程空间,编程开发者的网络收藏夹
学习永远不晚

命令行参数的解析:Flag 库详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

命令行参数的解析:Flag 库详解

在 Golang 程序中有很多种方法来处理命令行参数。

简单的情况下可以不使用任何库,直接使用 os.Args

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "os" 
  6.  
  7. func main() { 
  8.     if len(os.Args) > 0 { 
  9.         for index, arg := range os.Args { 
  10.             fmt.Printf("args[%d]=%v\n"index, arg) 
  11.         } 
  12.     } 

试着运行一下,第一个参数是执行文件的路径。

  1. $ go run demo.go hello world hello golang 
  2. args[0]=/var/folders/72/lkr7ltfd27lcf36d75jdyjr40000gp/T/go-build187785213/b001/exe/demo 
  3. args[1]=hello 
  4. args[2]=world 
  5. args[3]=hello 
  6. args[4]=golang 

从上面你可以看到,os.Args 只能处理简单的参数,而且对于参数的位置有严格的要求。对于一些比较复杂的场景,就需要你自己定义解析规则,非常麻烦。

如果真的遇上了所谓的复杂场景,那么还可以使用 Golang 的标准库 flag 包来处理命令行参数。

本文将介绍 Golang 标准库中 flag 包的用法。

1. 参数种类

根据参数是否为布尔型,可以分为两种:

  • 布尔型参数:如 --debug,后面不用再接具体的值,指定就为 True,不指定就为 False非布尔型参数
  • 非布尔型参数:非布尔型,有可能是int,string 等其他类型,如 --name jack ,后面可以接具体的参数值

根据参数名的长短,还可以分为:

  • 长参数:比如 --name jack 就是一个长参数,参数名前有两个 -
  • 短参数:通常为一个或两个字母(是对应长参数的简写),比如 -n ,参数名前只有一个 -

2. 入门示例

我先用一个字符串类型的参数的示例,抛砖引玉

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6.  
  7. func main(){ 
  8.     var name string 
  9.     flag.StringVar(&name"name""jack""your name"
  10.  
  11. flag.Parse()  // 解析参数 
  12.     fmt.Println(name

flag.StringVar 定义了一个字符串参数,它接收几个参数

  • 第一个参数 :接收值后,存放在哪个变量里,需为指针
  • 第二个参数 :在命令行中使用的参数名,比如 --name jack 里的 name
  • 第三个参数 :若命令行中未指定该参数值,那么默认值为 jack
  • 第四个参数:记录这个参数的用途或意义

运行以上程序,输出如下

  1. $ go run demo.go 
  2. jack 
  3.  
  4. $ go run demo.go --name wangbm 
  5. wangbm 

3. 改进一下

如果你的程序只接收很少的几个参数时,上面那样写也没有什么问题。

但一旦参数数量多了以后,一大堆参数解析的代码堆积在 main 函数里,影响代码的可读性、美观性。

建议将参数解析的代码放入 init 函数中,init 函数会先于 main 函数执行。

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6.  
  7. var name string 
  8.  
  9. func init()  { 
  10.     flag.StringVar(&name"name""jack""your name"
  11.  
  12. func main(){ 
  13.     flag.Parse() 
  14.     fmt.Println(name

4. 参数类型

当你在命令行中指定了参数,Go 如何解析这个参数,转化成何种类型,是需要你事先定义的。

不同的参数,对应着 flag 中不同的方法。

下面分别讲讲不同的参数类型,都该如何定义。

布尔型

实现效果:当不指定 --debug 时,debug 的默认值为 false,你一指定 --debug,debug 为赋值为 true。

  1. var debug bool 
  2.  
  3. func init()  { 
  4.     flag.BoolVar(&debug, "debug"false"是否开启 DEBUG 模式"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(debug) 

运行后,执行结果如下

  1. $ go run main.go  
  2. false 
  3. $ go run main.go --debug 
  4. true 

数值型

定义一个 age 参数,不指定默认为 18

  1. var age int 
  2.  
  3. func init()  { 
  4.     flag.IntVar(&age, "age", 18, "你的年龄"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(age) 

运行后,执行结果如下

  1. $ go run main.go  
  2. 18 
  3.  
  4. $ go run main.go --age 20 
  5. 20 

int64、 uint 和 float64 类型分别对应 Int64Var 、 UintVar、Float64Var 方法,也是同理,不再赘述。

字符串

定义一个 name参数,不指定默认为 jack

  1. var name string 
  2.  
  3. func init()  { 
  4.     flag.StringVar(&name"name""jack""你的名字"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(name

运行后,执行结果如下

  1. $ go run main.go  
  2. jack 
  3.  
  4. $ go run main.go --name wangbm 
  5. wangbm 

时间类型

定义一个 interval 参数,不指定默认为 1s

  1. var interval time.Duration 
  2.  
  3. func init()  { 
  4.     flag.DurationVar(&interval, "interval", 1 * time.Second"循环间隔"
  5.  
  6. func main(){ 
  7.     flag.Parse() 
  8.     fmt.Println(interval) 

验证效果如下

  1. $ go run main.go  
  2. 1s 
  3.  
  4. $ go run main.go --interval 2s 
  5. 2s 

5. 自定义类型

flag 包支持的类型有 Bool、Duration、Float64、Int、Int64、String、Uint、Uint64。

这些类型的参数被封装到其对应的后端类型中,比如 Int 类型的参数被封装为 intValue,String 类型的参数被封装为 stringValue。

这些后端的类型都实现了 flag.Value 接口,因此可以把一个命令行参数抽象为一个 Flag 类型的实例。下面是 Value 接口和 Flag 类型的代码:

  1. type Value interface { 
  2.     String() string 
  3.     Set(string) error 
  4.  
  5. // Flag 类型 
  6. type Flag struct { 
  7.     Name     string // name as it appears on command line 
  8.     Usage    string // help message 
  9.     Value    Value  // value as set 是个 interface,因此可以是不同类型的实例。 
  10.     DefValue string // default value (as text); for usage message 
  11.  
  12. func Var(value Value, name string, usage string) { 
  13.     CommandLine.Var(value, name, usage) 

想要实现自定义类型的参数,其实只要 Var 函数的第一个参数对象实现 flag.Value接口即可

  1. type sliceValue []string 
  2.  
  3.  
  4. func newSliceValue(vals []string, p *[]string) *sliceValue { 
  5.     *p = vals 
  6.     return (*sliceValue)(p) 
  7.  
  8. func (s *sliceValue) Set(val string) error { 
  9.          // 如何解析参数值 
  10.     *s = sliceValue(strings.Split(val, ",")) 
  11.     return nil 
  12.  
  13. func (s *sliceValue) String() string { 
  14.     return strings.Join([]string(*s), ","

比如我想实现如下效果,传入的参数是一个字符串,以逗号分隔,flag 的解析时将其转成 slice。

  1. $ go run demo.go -members "Jack,Tom" 
  2. [Jack Tom] 

那我可以这样子编写代码

  1. var members []string 
  2. type sliceValue []string 
  3.  
  4.  
  5. func newSliceValue(vals []string, p *[]string) *sliceValue { 
  6.     *p = vals 
  7.     return (*sliceValue)(p) 
  8.  
  9. func (s *sliceValue) Set(val string) error { 
  10.          // 如何解析参数值 
  11.     *s = sliceValue(strings.Split(val, ",")) 
  12.     return nil 
  13.  
  14.  
  15. func (s *sliceValue) String() string { 
  16.     return strings.Join([]string(*s), ","
  17.  
  18. func init()  { 
  19.     flag.Var(newSliceValue([]string{}, &members), "members""会员列表"
  20.  
  21. func main(){ 
  22.     flag.Parse() 
  23.     fmt.Println(members) 

有的朋友 可能会对 (*sliceValue)(p) 这行代码有所疑问,这是什么意思呢?

关于这个,其实之前在 【2.9 详细图解:静态类型与动态类型】有讲过,忘记了可以前往复习。

6. 长短选项

flag 包,在使用上,其实并没有没有长短选项之别,你可以看下面这个例子

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6.  
  7. var name string 
  8.  
  9. func init()  { 
  10.     flag.StringVar(&name"name""明哥""你的名字"
  11.  
  12. func main(){ 
  13.     flag.Parse() 
  14.     fmt.Println(name

通过指定如下几种参数形式

  1. $ go run main.go  
  2. 明哥 
  3. $ go run main.go --name jack 
  4. jack 
  5. $ go run main.go -name jack 
  6. jack 

一个 - 和两个 - 执行结果是相同的。

那么再加一个呢?

终于报错了。说明最多只能指定两个 -

  1. $ go run main.go ---name jack 
  2. bad flag syntax: ---name 
  3. Usage of /tmp/go-build245956022/b001/exe/main: 
  4.   -name string 
  5.         你的名字 (default "明哥"
  6. exit status 2 

7. 总结一下

flag 在绝大多数场景下,它是够用的,但如果要支持更多的命令传入格式,flag 可能并不是最好的选择。

那些在标准库不能解决的场景,往往会有相应的Go爱好者提供第三方解决方案。我所了解到的 cobra 就是一个非常不错的库。

 本文转载自微信公众号「Go编程时光」,可以通过以下二维码关注。转载本文请联系Go编程时光公众号。

 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

命令行参数的解析:Flag 库详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

命令行参数的解析:Flag 库详解

如果真的遇上了所谓的复杂场景,那么还可以使用 Golang 的标准库 flag 包来处理命令行参数。本文将介绍 Golang 标准库中 flag 包的用法。
命令行2024-12-03

Golang中命令行参数解析工具Flag包详解

Golang中的flag包用于解析命令行参数,提供了一个方便的接口来接收命令行参数,并将其转换为Go语言中的值。
GolangGo语言2024-11-30

从源码的角度看Go语言Flag库如何解析命令行参数!

Parse的代码里用到了一个,CommandLine共享变量,这就是内部库维护的FlagSet,所有的参数都会插到里面的变量地址向地址的指向赋值绑定。
Go语言Flag库2024-12-02

python命令行参数详解

在Python中,可以通过命令行传递参数给脚本。这些参数可以在脚本内部使用,以便根据不同的输入执行不同的操作。Python命令行参数的详解:1、位置参数:在命令行中按照顺序传递给脚本的参数,它们可以在脚本内部通过位置来访问;2、命令行选项:
python命令行参数详解
2023-12-18

Python中的命令行参数解析工具之docopt详解

前言 docopt 是一个开源的库,代码地址:https://github.com/docopt/docopt。它在 README 中就已经做了详细的介绍,并且还附带了很多例子可供学习,这篇文章也是翻译一下 README 中内容…… doc
2022-06-04

C#命令行参数解析库System.CommandLine的使用方法

这篇文章主要介绍了C#命令行参数解析库System.CommandLine的使用方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。命令行参数平常在日常的开发过程中,会经常用到
2023-06-15

node.js读取命令行参数详解

本文主要讲解了node.js如何获取命令行参数,有需要的朋友可以参考下
2022-11-13

详解Python中命令行参数argparse的常用命令

这篇文章主要为大家详细介绍了Python中命令行参数argparse的一些常用命令,文中的示例代码讲解详细,具有一定的学习价值,需要的可以了解一下
2023-01-29

node获取命令行中的参数详解

这篇文章主要为大家介绍了node获取命令行中的参数详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

python argparse命令行参数解析(推荐)

argparse是python用于解析命令行参数和选项的标准模块。 很多时候,需要用到解析命令行参数的程序,目的是在终端窗口输入训练的参数和选项。 argparse 模块可以让人轻松编写用户友好的命令行接口。 程序定义它需要的参数,然后 a
2022-06-02

linux shell命令行参数用法详解

习惯使用linux命令行来管理linux系统,例如: $ date 二 11 23 01:34:58 CST 1999 $用户登录时,实际进入了shell,它遵循一定的语法将输入的命令加以解释并传给系统。命令行中输入的第一个字必须是一个
2022-06-04

Python命令行参数解析的实用技巧

Python命令行参数解析的实用技巧在使用Python编写脚本时,经常需要从命令行获取参数。Python内置的argparse模块提供了一个简单而强大的实现命令行参数解析的工具。本文将介绍argparse的基本用法,并提供一些实用的技巧和
Python命令行参数解析的实用技巧
2024-02-03

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录