大部分Go程序运行在纯命令行的模式下,干什么全靠运行参数。

os.Args

程序获取运行他时给出的参数,可以通过os包来实现。先看代码:
文件:args.go

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "strconv"
  6. "strings"
  7. )
  8. func main() {
  9. args := os.Args
  10. arg1 := os.Args[1]
  11. // 你可以使用索引的方式来获取单个参数
  12. arg3 := os.Args[3]
  13. fmt.Println(args) // [./args a b c d]
  14. fmt.Println(arg1) // a
  15. fmt.Println(arg3) // c
  16. for idx, args := range os.Args {
  17. fmt.Println("参数" + strconv.Itoa(idx) + ":", args)
  18. }
  19. /**
  20. [./args a b c d]
  21. a
  22. c
  23. 参数0: ./args
  24. 参数1: a
  25. 参数2: b
  26. 参数3: c
  27. 参数4: d
  28. */
  29. // 输出切片的所有元素,还有更简洁的方式:
  30. fmt.Println(strings.Join(os.Args[1:], "\n"))
  31. fmt.Println(os.Args[1:])
  32. // 去掉第一个参数
  33. for idx, args := range os.Args[1:] {
  34. fmt.Println("参数:" + strconv.Itoa(idx) + ":", args)
  35. }
  36. /**
  37. hsd:testapi daysun$ go build args.go
  38. hsd:testapi daysun$ ./args a b c d
  39. [./args a b c d]
  40. a
  41. c
  42. 参数0: ./args
  43. 参数1: a
  44. 参数2: b
  45. 参数3: c
  46. 参数4: d
  47. a
  48. b
  49. c
  50. d
  51. [a b c d]
  52. 参数:0: a
  53. 参数:1: b
  54. 参数:2: c
  55. 参数:3: d
  56. */
  57. }

可以看到,命令行参数包括了程序路径本身,以及通常意义上的参数。
程序中 os.Args 的类型是 []string ,也就是字符串切片。
所以可以在for循环的range中遍历,还可以用 len(os.Args) 来获取其数量。

如果不想要输出 os.Args 的第一个值,也就是可执行文件本身的信息:

  1. for idx, args := range os.Args[1:] {...}

将range后面的切片,去掉第一个元素。
[

](https://blog.csdn.net/guanchunsheng/article/details/79612153)

flag包

flag包相比单纯的通过os.Args切片分析命令行参数,提供了更强的能力。

当我们写一些命令行小程序的时候,我们会需要解析命令行参数,以及可能会处理后面的参数。像 ls 等:

  1. ls -a 1

要是自己写这些参数解析啥的话真是十分的难受,还好golang已经帮我们写好了相关工具。这就是flag工具包。下面我们来详细说说。

常用方法

1.flag.Usage

输出使用方法,如linux下 ls -h的帮助输出

2.flag.Type(参数名, 默认值, 使用提示)

Type为类型 如String, Int, Uint 调用相应的flag.Sring flag.Int flag.Uint方法
方法返回相应类型的指针

3.flag.Type(指针, 参数名, 默认值, 使用提示)

与flag.Type方法基本相同,不同的是多一个指针参数,将使用传入的指针,不会再创建指针返回

4.flag.Args

返回解析完命令行参数后的其他参数,如./sh -name cqh a1 a2,将返回a1 a2

5.flag.Parse

执行解析

配置flag

配置flag主要有两类方法:

  1. 1. func XXX(name string, value xxx, usage string) *xxx
  2. 2. func XXXVar(p *xxx, name string, value xxx, usage string)

其中XXX为各个类型名,有:bool、duration、float64、int64、int、uint、uint64、string等

区别:

  1. 直接返回指向对应类型指针并分配对应指针指向的对象,可以直接通过解引用来获取转换后的对应值。
  2. 指定指针指向的对象
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. )
  6. // 第1种写法
  7. func main() {
  8. // 参数 默认值 说明
  9. // 返回指向对应类型指针并分配对应指针指向的对象
  10. pi := flag.Int("a", 10, "apple")
  11. flag.Parse()
  12. fmt.Printf("%v\n", *pi)
  13. /**
  14. 运行:
  15. $ go run flagDemo.go -a 20
  16. 20
  17. // 默认值
  18. $ go run flagDemo.go
  19. 10
  20. */
  21. }
  22. // 第2种写法 等价写法
  23. func main2() {
  24. // 指定指针指向的对象
  25. var i int
  26. flag.IntVar(&i, "a", 10, "apple")
  27. flag.Parse()
  28. fmt.Printf("%v\n", i)
  29. }

示例代码

新建 flagTest.go

  1. package main
  2. import (
  3. "fmt"
  4. "flag"
  5. )
  6. func main() {
  7. namePtr := flag.String("name", "username", "姓名")
  8. agePtr := flag.Int("age", 18, "年龄")
  9. musclePtr := flag.Bool("muscle", true, "是否有肌肉")
  10. var email string
  11. flag.StringVar(&email, "email", "white@taobao.com", "邮箱")
  12. flag.Parse()
  13. args := flag.Args()
  14. fmt.Println("name:", *namePtr)
  15. fmt.Println("age:", *agePtr)
  16. fmt.Println("muscle:", *musclePtr)
  17. fmt.Println("email:", email)
  18. fmt.Println("args:", args)
  19. }

编译运行

  1. $ go build flagTest.go
  2. $ ./flagTest -h
  3. Usage of ./flagTest:
  4. -age int
  5. 年龄 (default 18)
  6. -email string
  7. 邮箱 (default "white@taobao.com")
  8. -muscle
  9. 是否有肌肉 (default true)
  10. -name string
  11. 姓名 (default "username")
  12. #默认值
  13. $ ./flagTest
  14. name: username
  15. age: 18
  16. muscle: true
  17. email: white@taobao.com
  18. args: []
  19. # 命令行参数
  20. $ ./flagTest -name 肌肉男 -age 20 -email 123@qq.com 哈哈 呵呵 嘿嘿
  21. name: 肌肉男
  22. age: 20
  23. muscle: true
  24. email: 123@qq.com
  25. args: [哈哈 呵呵 嘿嘿]

NewFlagSet

使用 NewFlagSet 函数声明一个子命令, 然后为这个子命令定义一个专用的 flag。
对于不同的子命令,我们可以定义不同的 flag。
子命令应作为程序的第一个参数传入。

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. )
  7. func main() {
  8. // 声明一个子命令fooCmd
  9. fooCmd := flag.NewFlagSet("foo", flag.ExitOnError)
  10. // 子命令专用tag
  11. fooEnable := fooCmd.Bool("enable", false, "enable")
  12. fooName := fooCmd.String("name", "", "name")
  13. barCmd := flag.NewFlagSet("bar", flag.ExitOnError)
  14. barLevel := barCmd.Int("level", 0, "level")
  15. if len(os.Args) < 2 {
  16. fmt.Println("expected 'foo' or 'bar' subcommands")
  17. os.Exit(1)
  18. }
  19. switch os.Args[1] {
  20. case "foo":
  21. fooCmd.Parse(os.Args[2:])
  22. fmt.Println("subcommand 'foo'")
  23. fmt.Println(" enable:", *fooEnable)
  24. fmt.Println(" name:", *fooName)
  25. fmt.Println(" tail:", fooCmd.Args())
  26. case "bar":
  27. barCmd.Parse(os.Args[2:])
  28. fmt.Println("subcommand 'bar'")
  29. fmt.Println(" level:", *barLevel)
  30. fmt.Println(" tail:", barCmd.Args())
  31. default:
  32. fmt.Println("expected 'foo' or 'bar' subcommands")
  33. os.Exit(1)
  34. }
  35. }
  1. #编译
  2. $ go build flagNewFlagSet.go
  3. #调用 foo 子命令
  4. $ ./flagNewFlagSet foo -enable -name=joe a1 a2
  5. subcommand 'foo'
  6. enable: true
  7. name: joe
  8. tail: [a1 a2]
  9. #调用 bar 子命令
  10. $ ./flagNewFlagSet bar -level 8 a1
  11. subcommand 'bar'
  12. level: 8
  13. tail: [a1]
  14. # bar 不接受 foo 的 flag(enable)参数
  15. $ ./flagNewFlagSet bar -nable a1
  16. flag provided but not defined: -nable
  17. Usage of bar:
  18. -level int
  19. level

总结

  1. flag 主要提供了一种参数解析方式,可以根据以注册命令参数, 解析不同的输出对象, 以获取所需信息。
  2. flag 主要包含
    1. 对象的定义及工厂函数
    2. 各类型参数注册方法
    3. 信息获取函数

模块默认提供命令行的快捷方法。

参考: