17.2 命令行-标志的类型、自定义帮助信息、子命令

1. 命令行标志的类型

针对标志值的每一种数据类型,flag包都提供了相对应的函数。

  • name := flag.String("name", "Anonymous", "Your name")

// 名字,字符串型

age := flag.Int("age", 20, "Your age") // 年龄,整型

female := flag.Bool("female", false, "You are female")

// 是否女性,布尔型

  • name、age和female的数据类型分别为*string、*int和*bool(返回的是指针,谨记)

布尔型标志,指定了取true,没指定取默认值,因此默认值应该为false。

  • main.exe -name Susan -age 30 -female
    • female -> true

                注:在此需要说明一下bool类型的标志及标志值的问题

                bool类型的参数有下面几种写法:

                --flag // 等同于 --flag==true

                --flag = value

                --flag value // 这种写法只有在没有设置默认值时才生效

  • main.exe -name George -age 40

                female -> false

//解析不同类型的命令行标志
// flag包为解析不同类型的命令行标志提供了不同的函数
package main
import (
    "flag"
    "fmt"
)
func main() {
    name := flag.String("name", "Anonymous", "Your name")
    age := flag.Int("age", 20, "Your age")
    female := flag.Bool("female", false, "You are female")

    flag.Parse()
    fmt.Println("Your name is", *name)
    fmt.Println("Your age is", *age)
    if *female {
        fmt.Println("You are female")
    } else {
        fmt.Println("You are male")
    }
}
// 打印输出:
 PS > ./main.exe -name George -age 40
 Your name is George
 Your age is 40
 You are male

 PS > ./main.exe -name Susan -age 30 -female
 Your name is Susan
 Your age is 30
 You are female

 2. 自定义帮助信息

调用flag包的String、Int、Bool等函数时所提供的最后一个参数,将用于当用户输入错误或通过下列标志寻求帮助时,生成帮助信息。

  • -h
  • --h
  • -help
  • --help

如果将flag包导出变量Usage设置为一个函数,当用户输入错误或寻求帮助时,该函数将被调用。通过实现该函数,程序员可以自己定义帮助信息。

  • flag.Usage = func() {

                usageText := ... // 组织帮助信息字符串

                fmt.Fprintf(os.Stderr, "%s\n", usageText) // 将帮助信息输出到标准错误

        }

//显示自定义的帮助文本
// 用自己的实现覆盖flag包里的Usage函数,每当命令行
// 标志解析失败都会调用该函数,显示自定义的帮助信息
package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    flag.Usage = func() {	// 为Usage自定义函数并赋值,实现自定义帮助文本
        fmt.Fprintf(os.Stderr,
        `Usage: %v [OPTION]
+---------+----------------+-----------+
| OPTION  | DESCRIPTION    | DEFAULT   |
+---------+----------------+-----------+
| -name   | Your name      | Anonymous |
| -age    | Your age       | 20        |
| -female | You are female | false     |
+---------+----------------+-----------+
`, os.Args[0])
    }

    name := flag.String("name", "Anonymous", "")
    age := flag.Int("age", 20, "")
    female := flag.Bool("female", false, "")
    flag.Parse()
	fmt.Println("Your name is", *name)
    fmt.Println("Your age is", *age)
    if *female {
        fmt.Println("You are female")
    } else {
        fmt.Println("You are male")
    }
}
// 打印输出:
 PS G:\GoWorkspace\src\cli\usage> ./main.exe --help
 Usage: G:\GoWorkspace\src\cli\usage\main.exe [OPTION]
 +---------+----------------+-----------+
 | OPTION  | DESCRIPTION    | DEFAULT   |
 +---------+----------------+-----------+
 | -name   | Your name      | Anonymous |
 | -age    | Your age       | 20        |
 | -female | You are female | false     |
 +---------+----------------+-----------+ 

 3. 子命令

很多命令行程序都支持子命令,而每个子命令又带有自己的标志集,例如:

  • main.exe uppercase -l golang  // uppercase是子命令,-l是子命令标志名,golang是标志值,功能是将标志值转化为大写字符串。
  • main.exe lowercase -u GOLANG

flag包的NewFlagSet函数可用于创建针对特定子命令的标志集。

  • uppercase := flag.NewFlagSet("uppercase", flag.ExitOnError)
  • lowercase := flag.NewFlagSet("lowercase", flag.ExitOnError)

其中第一个参数为子命令名,第二个参数则指定了针对错误处理方式,其返回值是与第一个参数相对应的子命令的标志集。每个子命令对应的标志集是独立的。

  • ContinueOnError - 忽略错误,继续执行
  • ExitOnError - 出现错误,以状态码2退出
  • PanicOnError - 出现错误,引发恐慌

在获得针对每个子命令的标志集以后,再通过switch语句处理不同的子命令。

  • switch os.Args[1] { // 子命令名在Args切片中的下标是1,下标0是命令行程序文件路径
  • case "uppercase":
  •         处理uppercase子命令
  • case "lowercase":
  •         处理lowercase子命令
  • default:
  •         处理无效子命令
  • }
  • 注:hyperchain的main启动文件就是这么玩的。

针对每个子命令的处理,可以借助相应的标志集,以类似处理命令行标志的方法,根据标志名获取相应的标志值

  • l := uppercase.String("l", "hello world", "A string of text to be uppercased") // uppercase即为标志集,通过标志值来定义不同的处理方法;
  • uppercase.Parse(os.Args[2:]) // 子命令的参数在Args切片中的下标从2开始;
  • fmt.Println(strings.ToUpper(*l))
  • u := lowercase.String("u", "HELLO WORLD", "A string of text to be lowercased")
  • lowercase.Parse(os.Args[2:]) // Args切片中下标1对应的是子命令名
  • fmt.Println(strings.ToLower(*u))

对于无效子命令,可以简单地打印帮助信息

  • flag.Usage()
// 处理子命令
// flag包的NewFlagSet函数可创建独立标
// 志集,以用于解析子命令的命令行标志 
//
// 子命令标志集 = flag.NewFlagSet(子命令, 错误处理)
// switch os.Args[1] {
// case 子命令:
//     标志指针 = 子命令标志集.String(标志名, 默认值,
//         帮助文本)
//     子命令标志集.Parse(os.Args[2:])
//     子命令处理 
// default:
//     报告错误
// }
//   0    1    2    ...
// 命令 子命令 -标志名 标志值[默认值]
//                  ^
//                  |
//               标志指针 
package main
import (
  "flag"
  "fmt"
  "os"
  "strings"
)
func main() {
  flag.Usage = func() {
    fmt.Fprintf(os.Stderr, `Usage: %v [COMMAND]
+-----------+--------------------+
| COMMAND   | DESCRIPTION        |
+-----------+--------------------+
| uppercase | Uppercase a string |
| lowercase | Lowercase a string |
+-----------+--------------------+
`, os.Args[0])
  }
if len(os.Args) < 2 {
    flag.Usage()
    return
  }

  uppercase := flag.NewFlagSet("uppercase",
    flag.ExitOnError)
  lowercase := flag.NewFlagSet("lowercase",
    flag.ExitOnError)

  switch os.Args[1] {
  case "uppercase":
    l := uppercase.String("l", "hello world",
      "A string of text to be uppercased")
    uppercase.Parse(os.Args[2:])
    fmt.Println(strings.ToUpper(*l))
	case "lowercase":
    u := lowercase.String("u", "HELLO WORLD",
      "A string of text to be lowercased")
    lowercase.Parse(os.Args[2:])
    fmt.Println(strings.ToLower(*u))

  default:
    flag.Usage()
  }
}
// 打印输出:
PS > ./main.exe uppercase -l golang 
 GOLANG
 PS > ./main.exe lowercase -u GOLANG
 golang 

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值