还不会命令行?用Go Flag自写命令行程序

时间:2022-07-22
本文章向大家介绍还不会命令行?用Go Flag自写命令行程序,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

作者 | 陌无崖

转载请联系授权

内容目录

Go flag包详解前言入门案例源码包解析定义flag参数完整案例

前言

相信大家都用到过命令行工具。尤其当我们在用Linux进行代码开发时,会使用很多工具,比如下面的这张图。那么自己如何开发一个命令行工具呢?

image.png

入门案例

在这个案例中我们需要用到Go官方包中的flag解析包。新建一个flag.go

package main

import (
    "flag"
    "fmt"
)

// 定义命令行参数对应的变量,这三个变量都是指针类型
var cliName = flag.String("name", "nick", "Input Your Name")
var cliAge = flag.Int("age", 28, "Input Your Age")
var cliGender = flag.String("gender", "male", "Input Your Gender")

// 定义一个值类型的命令行参数变量,在 Init() 函数中对其初始化
// 因此,命令行参数对应变量的定义和初始化是可以分开的
var cliFlag int

func Init() {
    flag.IntVar(&cliFlag, "flagname", 1234, "Just for demo")
}
func main() {
    // 初始化变量 cliFlag
    Init()
    // 把用户传递的命令行参数解析为对应变量的值
    flag.Parse()

    // flag.Args() 函数返回没有被解析的命令行参数
    // func NArg() 函数返回没有被解析的命令行参数的个数
    fmt.Printf("args=%s, num=%dn", flag.Args(), flag.NArg())
    for i := 0; i != flag.NArg(); i++ {
        fmt.Printf("arg[%d]=%sn", i, flag.Arg(i))
    }

    // 输出命令行参数
    fmt.Println("name=", *cliName)
    fmt.Println("age=", *cliAge)
    fmt.Println("gender=", *cliGender)
    fmt.Println("flagname=", cliFlag)
}

编译我们的源文件为二进制

 go build .flag.go

测试以下

.flag.exe help

image.png

 .flag.exe -name yuwei 

image.png

源码包解析

定义flag参数

1、通过flag.Xxx()。Xxx可以指String、Bool、Int等基本数据类型。使用这种方式会相应的返回一个指针。如:

// 定义命令行参数对应的变量,这三个变量都是指针类型
var cliName = flag.String("name", "nick", "Input Your Name")
var cliAge = flag.Int("age", 28, "Input Your Age")
var cliGender = flag.String("gender", "male", "Input Your Gender")

函数中的参数分别代表的含义为:命令行参数、参数的默认值、参数的提示或者解释。

2、通过flag.XxxVar()方法将flag绑定到一个变量,该种方式返回值类型,如:

var cliFlag int
var flag.IntVar(&cliFlag, "flagname", 1234, "Just for demo")

函数中的参数分别代表的含义为:待赋值的变量、命令行参数、参数的默认值、参数的提示或者解释。

3、通过flag.Var()绑定自定义类型,自定义类型需要实现Value接口(Receives必须为指针),如下案例

  • 新建一个type.go
type self struct {
    Address string
    Area    string
}
func (s *self) String() string {
    return fmt.Sprintf("%s", *s)
}
func (s *self) Set(value string) error {
    return nil
}
  • 定义参数
var selfFlag self
var flag.Var(&selfFlag, "self", "please input address,area eg: "beijing china"")

这里需要注意的是实现接口Value中函数String()代表定义默认值。Set()函数是对参数值的接收对其进行操作。

完整案例

main.go

package main

import (
    "flag"
    "fmt"
)

// 定义命令行参数对应的变量,这三个变量都是指针类型
var cliName = flag.String("name", "nick", "Input Your Name")
var cliAge = flag.Int("age", 28, "Input Your Age")
var cliGender = flag.String("gender", "male", "Input Your Gender")

// 定义一个值类型的命令行参数变量,在 Init() 函数中对其初始化
// 因此,命令行参数对应变量的定义和初始化是可以分开的
var cliFlag int

var selfFlag self

func Init() {
    flag.IntVar(&cliFlag, "flagname", 1234, "Just for demo")
    flag.Var(&selfFlag, "self", "please input address,area eg: "beijing china"")
}
func main() {
    // 初始化变量 cliFlag
    Init()
    // 把用户传递的命令行参数解析为对应变量的值
    flag.Parse()

    // flag.Args() 函数返回没有被解析的命令行参数
    // func NArg() 函数返回没有被解析的命令行参数的个数
    fmt.Printf("args=%s, num=%dn", flag.Args(), flag.NArg())
    for i := 0; i != flag.NArg(); i++ {
        fmt.Printf("arg[%d]=%sn", i, flag.Arg(i))
    }

    // 输出命令行参数
    fmt.Println("name=", *cliName)
    fmt.Println("age=", *cliAge)
    fmt.Println("gender=", *cliGender)
    fmt.Println("flagname=", cliFlag)
    fmt.Println("selfFlag=", selfFlag)
}

type.go

/*
 * @Author: your name
 * @Date: 2019-11-22 15:38:48
 * @LastEditTime: 2019-11-22 19:19:56
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: GoWebd:praticetflagdemotype.go
 */
package main

import "fmt"

import "errors"

import "strings"

type self struct {
    Address string
    Area    string
}

func (s *self) String() string {
    *s = self{"Beingjing", "China"}
    return fmt.Sprintf("%s", *s)
}
func (s *self) Set(value string) error {
    if len(value) <= 0 {
        return errors.New("参数为空,请输入正确的参数")
    }
    data := strings.Split(value, " ")
    *s = self{
        data[0],
        data[1],
    }
    fmt.Println(*s)
    return nil
}

运行我们程序

image.png

image.png