go - flag包(处理命令行参数小能手)

2023-11-08

前言

在golang中有很多方法来处理命令行参数,简单情况下可以不使用任何库,直接使用os.Args;
但是golang标准库提供了flag包来专门处理命令行参数
当然还有第三方提供的处理命令行参数的库cobra、cli可以参考。

flag包绑定解析参数的三种定义方式

(1) flag.Xxx() 例如:flag.Int, flag.String, 返回解析变量类型的指针

package main

import (
    "flag"
    "fmt"
)

var (
	host *string
	port *int
)

func init()  {
	host = flag.String("host", "127.0.0.1", "请输入host地址")
	port = flag.Int("port", 3306, "请输入端口号")
}

func main() {
    flag.Parse() // 解析参数
    fmt.Printf("%s:%d\n", *host, *port)
}
执行:go run main.go
输出:127.0.0.1:3306

执行: go run main.go -host=192.168.0.1 -port=8080 
输出:192.168.0.1:8080

执行:go run main.go -host 192.168.0.1
输出:192.168.0.1:3306

执行:go run main.go -host=192.168.0.1 -port
输出:invalid value "" for flag -port: parse error
     Usage of xxxxx/exe/main:
        -host string
             请输入host地址 (default "127.0.0.1")
        -port int
             请输入端口号 (default 3306)
     exit status 2

执行:go run main.go -h
输出:Usage of xxxxx/exe/main:
        -host string
            请输入host地址 (default "127.0.0.1")
        -port int
            请输入端口号 (default 3306)

(2) flag.XxxVar() 例如:flag.IntVar, flag.StringVar 获取解析变量类型的值

package main

import (
	"flag"
	"fmt"
)

var (
	host string
	port int
)

func init() {
	flag.StringVar(&host, "host", "127.0.0.1", "请输入host地址")
	flag.IntVar(&port, "port", 3306, "请输入端口号")
}

func main() {
	flag.Parse() // 解析参数
	fmt.Printf("%s:%d\n", host, port)
}
执行效果同上

(3)自定义参数解析flag.Var()

我们可以看下flag.go源码:

func Var(value Value, name string, usage string) {
    CommandLine.Var(value, name, usage)
}

type Value interface {
    String() string
    Set(string) error
}

使用flag.Var函数第一个参数我们需要传入一个Value类型的值,Value是一个接口类型,定义了两个方法。
接下来我们去实现这两个方法:

package main

import (
	"flag"
	"fmt"
	"strings"
)

// 自定义类型
type HandsomeBoys []string

// 实现String()方法
func (h *HandsomeBoys) String() string {
	return fmt.Sprintf("%v", *h)
}

// 实现Set方法,Set接口决定了如何解析flag的值
func (h *HandsomeBoys) Set(s string) error {
	for _, v := range strings.Split(s, ",") {
		*h = append(*h, v)
	}
	return nil
}

// 定义一个HandsomeBoys类型的变量
var boys HandsomeBoys

func init() {
	// 绑定变量boys
	flag.Var(&boys, "boys", "请输入一组帅气的男孩名称:-boys=彭于晏,吴彦祖")
}

func main() {
	flag.Parse()
	fmt.Println(boys)
}
输入:go run var/main.go
输出:[]

输入:go run var/main.go -boys=吴彦波,胡歌
输出:[吴彦波 胡歌]

拓展

1、go的os模块

使用 os.Args 也能获取命令行参数,但是这个功能有点欠缺。
例如不能接收像-u root -p 3306这样指定key的值,只能接收像root 3306这样的方式。
示例:

package main

import (
	"fmt"
	"os"
)

var cmdArgs []string

func init()  {
	cmdArgs = os.Args
}

func main() {
	for index, value := range cmdArgs {
		fmt.Printf("索引:%v,value值:%v\n", index, value)
	}
}
输入:go build -o main.exe main.go 
     ./main.exe root 3306 
输出:索引:0,value值:./main.exe
     索引:1,value值:root
     索引:2,value值:3306

注:返回的cmdArgs是一个切片,第一个值是自己的文件名。
如果不想要自己第一个值,直接 cmdArgs = os.Args[1:] 即可。

2、viper + flag

有意思的是,可以将viper同flag结合使用。
示例:

package main

import (
	"flag"
	"fmt"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

func main() {
	// using standard library "flag" package
	flag.String("flagname", "root", "help message for flagname")

	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
	pflag.Parse()
	viper.BindPFlags(pflag.CommandLine)

	myFlagname := viper.GetString("flagname") // retrieve value from viper
	fmt.Println("myFlagname:", myFlagname)
}
输入:go run flagUtil.go -h
输出:Usage of xxxxx/exe/flagUtil:
        --flagname string   help message for flagname (default "root")
     pflag: help requested

输入:go run flagUtil.go
输出:myFlagname: 1234

输入:go run flagUtil.go --flagname 吴彦波
输出:myFlagname: 吴彦波
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go - flag包(处理命令行参数小能手) 的相关文章