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

本文介绍了Go语言中处理命令行参数的多种方法,包括使用标准库flag包的不同方式及其实现原理,还展示了如何利用viper进行配置管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在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: 吴彦波
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值