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