go flag

flag 用法参考:

https://golang.google.cn/pkg/flag/


1. 命令源码文件怎样接收参数

package main

import (
    "flag" #导入flag包
    "fmt"
)

var name string

func init(){
    flag.StringVar(&name,"name","everyone","The greting object") # 
}

func main(){
    flag.Parse() #函数flag.Parse用于真正解析命令参数,并把它们的值赋给相应的变量。
    fmt.Printf("hello,%s!\n",name)
}

函数flag.StringVar接受 4 个参数。

第 1 个参数是用于存储该命令参数值的地址,具体到这里就是在前面声明的变量name的地址了,由表达式&name表示。

第 2 个参数是为了指定该命令参数的名称,这里是name。

第 3 个参数是为了指定在未追加该命令参数时的默认值,这里是everyone。

第 4 个函数参数,即是该命令参数的简短说明了,这在打印命令说明时会用到。


go run demo2.go -name="huaihe"
Hello, huaihe!


2. 怎样在运行命令源码文件的时候传入参数,又怎样查看参数的使用说明


如果想查看该命令源码文件的参数说明,可以这样做:

go run demo2.go --help
Usage of /var/folders/4w/lv_wjx0d3b3ff30w0bn_65xc0000gn/T/go-build966482306/b001/exe/demo2: #构建上述命令源码文件时临时生成的可执行文件的完整路径
  -name string
        The greeting object. (default "everyone")
exit status 2


果我们先构建这个命令源码文件再运行生成的可执行文件,像这样:

go build demo2.go
ls demo2
demo2
./demo2 --help
Usage of ./demo2:
  -name string
        The greeting object. (default "everyone")


3. 怎样自定义命令源码文件的参数使用说明

这有很多种方式,最简单的一种方式就是对变量flag.Usage重新赋值。flag.Usage的类型是func(),即一种无参数声明且无结果声明的函数类型。flag.Usage变量在声明时就已经被赋值了,所以我们才能够在运行命令go run demo2.go --help时看到正确的结果。注意,对flag.Usage的赋值必须在调用flag.Parse函数之前。

package main

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

var name string

func init() {
    flag.StringVar(&name, "name", "everyone", "The greting object")
}

func main() {
    flag.Usage = func() {
        fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
        flag.PrintDefaults()
    }
    flag.Parse()
    fmt.Printf("hello,%s!\n", name)
}
go run demo2.go --help
#这里并没有打印临时文件位置,而是打印了os.Stderr,因为此时os.Stderr为空
Usage of question:
  -name string
        The greting object (default "everyone")
exit status 2

再深入一层,我们在调用flag包中的一些函数(比如StringVar、Parse等等)的时候,实际上是在调用flag.CommandLine变量的对应方法。

flag.CommandLine相当于默认情况下的命令参数容器。所以,通过对flag.CommandLine重新赋值,我们可以更深层次地定制当前命令源码文件的参数使用说明。

现在我们把main函数体中的那条对flag.Usage变量的赋值语句注销掉,然后在init函数体的开始处添加如下代码:

package main

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

var name string

func init() {
    flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError)
    flag.CommandLine.Usage = func() {
        fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
        flag.PrintDefaults()
    }
    flag.StringVar(&name, "name", "everyone", "The greting object")
}

func main() {
    flag.Parse()
    fmt.Printf("hello,%s!\n", name)
}
go run demo2.go --help
Usage of question:
  -name string
        The greting object (default "everyone")
exit status 2

其输出会与上一次的输出的一致。不过后面这种定制的方法更加灵活。比如,当我们把为flag.CommandLine赋值的那条语句改为:

package main

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

var name string

func init() {
    flag.CommandLine = flag.NewFlagSet("", flag.PanicOnError) #注意这里修改为flag.PanicOnError
    flag.CommandLine.Usage = func() {
        fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
        flag.PrintDefaults()
    }
    flag.StringVar(&name, "name", "everyone", "The greting object")
}

func main() {
    flag.Parse()
    fmt.Printf("hello,%s!\n", name)
}


这是由于我们在这里传给flag.NewFlagSet函数的第二个参数值是flag.PanicOnError。flag.PanicOnError和flag.ExitOnError都是预定义在flag包中的常量。

flag.ExitOnError的含义是,告诉命令参数容器,当命令后跟--help或者参数设置的不正确的时候,在打印命令参数使用说明后以状态码2结束当前程序。

状态码2代表用户错误地使用了命令,而flag.PanicOnError与之的区别是在最后抛出“运行时恐慌(panic)”。

上述两种情况都会在我们调用flag.Parse函数时被触发。顺便提一句,“运行时恐慌”是 Go 程序错误处理方面的概念。关于它的抛出和恢复方法,我在本专栏的后续部分中会讲到。


下面再进一步,我们索性不用全局的flag.CommandLine变量,转而自己创建一个私有的命令参数容器。我们在函数外再添加一个变量声明:

我们把对flag.StringVar的调用替换为对cmdLine.StringVar调用,再把flag.Parse()替换为cmdLine.Parse(os.Args[1:])。其中的os.Args[1:]指的就是我们给定的那些命令参数。这样做就完全脱离了flag.CommandLine。*flag.FlagSet类型的变量cmdLine拥有很多有意思的方法

package main

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

var name string

// 方式3。
var cmdLine = flag.NewFlagSet("question", flag.ExitOnError)

func init() {
    // 方式3。
    cmdLine.StringVar(&name, "name", "everyone", "The greeting object.")
}

func main() {
    // 方式3。
    cmdLine.Parse(os.Args[1:])
    fmt.Printf("Hello, %s!\n", name)
}
go run demo3.go --help
Usage of question:
  -name string
        The greeting object. (default "everyone")
exit status 2

go run demo3.go --name="test"
Hello, test!


这样做的好处依然是更灵活地定制命令参数容器。但更重要的是,你的定制完全不会影响到那个全局变量flag.CommandLine。


上一篇:JavaScript003,用法


下一篇:Hadoop----hdfs dfs常用命令的使用