【Golang | flag】go run xxx.go -h | grep xx为什么得不到预期结果?原来默认打印到标准错误~

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函数,给命令行默认参数集CommandLineUsage字段赋值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:修改CommandLineoutputos.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 ~]#

你可能感兴趣的:(Golang,golang,开发语言,后端)