1. 现象
这两天学习go语言flag
包的基本用法,代码写好了
package main
import "flag"
var (
name = flag.String("name", "tian", "default name")
age = flag.String("age", "10", "default age")
sex = flag.String("sex", "male", "default sex")
)
func main() {
flag.Parse()
}
执行下试试效果,能得到想要的结果
[root@k8s-master ~]# go run main.go -h
Usage of /tmp/go-build2504421077/b001/exe/main:
-age string
default age (default "10")
-name string
default name (default "tian")
-sex string
default sex (default "male")
[root@k8s-master ~]#
但是如果-h
输出的帮助信息太多,想通过grep
过滤下,却发现还是输出了全部的帮助信息
[root@k8s-master ~]# go run main.go -h | grep age
Usage of /tmp/go-build3039901848/b001/exe/main:
-age string
default age (default "10")
-name string
default name (default "tian")
-sex string
default sex (default "male")
[root@k8s-master ~]#
2. 原因
查看源码,可以发现flag.go
有个init
函数,给命令行默认参数集CommandLine
的Usage
字段赋值commandLineUsage
// CommandLine is the default set of command-line flags, parsed from os.Args.
// The top-level functions such as BoolVar, Arg, and so on are wrappers for the
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
func init() {
// Override generic FlagSet default Usage with call to global Usage.
// Note: This is not CommandLine.Usage = Usage,
// because we want any eventual call to use any updated value of Usage,
// not the value it has when this line is run.
CommandLine.Usage = commandLineUsage
}
func commandLineUsage() {
Usage()
}
问题的关键就是这个Usage
函数,查看注释,可以明显看到这么一段Usage prints a usage message documenting all defined command-line flags to CommandLine's output, which by default is os.Stderr.
,意思就是Usage负责打印所有定义过的命令行参数到标准错误
// NOTE: Usage is not just defaultUsage(CommandLine)
// because it serves (via godoc flag Usage) as the example
// for how to write your own usage function.
// Usage prints a usage message documenting all defined command-line flags
// to CommandLine's output, which by default is os.Stderr.
// It is called when an error occurs while parsing flags.
// The function is a variable that may be changed to point to a custom function.
// By default it prints a simple header and calls PrintDefaults; for details about the
// format of the output and how to control it, see the documentation for PrintDefaults.
// Custom usage functions may choose to exit the program; by default exiting
// happens anyway as the command line's error handling strategy is set to
// ExitOnError.
var Usage = func() {
fmt.Fprintf(CommandLine.Output(), "Usage of %s:\n", os.Args[0])
PrintDefaults()
}
3. 解决
明白了原因后,这里有两种解决方法。
方法1:鉴于grep
是过滤标准输出的。既然Usage
默认打印到标准错误,那么我们通过2>&1
将标准错误重定向标准输出就行
[root@k8s-master ~]# go run main.go -h 2>&1 | grep age
Usage of /tmp/go-build3848435230/b001/exe/main:
-age string
default age (default "10")
[root@k8s-master ~]#
方法2:修改CommandLine
的output
为os.Stdout
,flag包也提供了具体方法SetOutput
// SetOutput sets the destination for usage and error messages.
// If output is nil, os.Stderr is used.
func (f *FlagSet) SetOutput(output io.Writer) {
f.output = output
}
修改下main.go代码,如下
package main
import (
"flag"
"os"
)
var (
name = flag.String("name", "tian", "default name")
age = flag.String("age", "10", "default age")
sex = flag.String("sex", "male", "default sex")
)
func main() {
flag.CommandLine.SetOutput(os.Stdout)
flag.Parse()
}
现在再来试试效果,bingo!
[root@k8s-master ~]# go run main.go -h | grep age
Usage of /tmp/go-build3453446919/b001/exe/main:
-age string
default age (default "10")
[root@k8s-master ~]#