美文网首页
Go语言 命令行解析(二)

Go语言 命令行解析(二)

作者: 桂成林 | 来源:发表于2020-04-17 22:45 被阅读0次

    今天我们继续讲解Go语言中命令行,当我们在解析命令行传递的参数时通常会想用最简单的方法来解析自己行用到的命令行参数,那么urfave/cli可以帮助我们快速的解析命令行参数,它是一个简单快速的命令行包,用于在Go语言中构建命令行应用程序,目的是使开发人员能够以表达的方式编写快速分发的命令行应用程序,urfave/cli库抽象出来:FlagCommand,SubCommand等模块,用户只需要设置模块信息,参数的解析和关联就可以,帮助信息自动生成。

    在C语言中可以通过getopt(int argc, char * const argv[], const char *optstring)来完成参数解析,这里不做示例,有兴趣的同学可以自己动手尝试一下。

    安装urfave/cli:

    go get github.com/urfave/cli
    

    包引用方法:

    import "github.com/urfave/cli" //引入cli包
    

    urfave/cli包中几个重要的方法:

    cli.NewApp()    // 创建一个cli实例
    Run()       // 程序入口,执行Run后分析参数切片和路由
    app.Commands    // 要执行的命令列表
    app.Before  // 运行命令之前执行的内容
    app.After   // 运行命令之后执行的内容
    Subcommands    // 子命令
    

    好,开始我们演示,今天的演示示例有点长,项目目录结构如下:

    #tree
    .
    |-- commands
    |   |-- api
    |   |   `-- api.go        // api commands
    |   `-- service
    |       `-- service.go    // 服务 commands
    |-- go_cli.go             // main入口
    |-- go.mod                // go module管理包
    |-- go.sum
    `-- webservice
        |-- bin
        |   `-- webservice
        `-- webservice.go     // web服务类
    

    首先,定义webservice类:

    webservice类主要完成几个功能:构造函数,释放资源函数,ApiService方法和Service方法。

    package webservice
    
    import "fmt"
    
    // web service 类
    type WebService struct {
        Config  string
        Port    int
        LogFile string
    }
    
    // 返回web service 实例
    func NewWebService(config, logFile string, port int) *WebService {
    
        var ws = &WebService{
            Port:    port,
            Config:  config,
            LogFile: logFile,
        }
        return ws
    }
    
    // 释放资源
    func (ws *WebService) Freed() {
    
    }
    
    // API调用启动方式
    func (ws *WebService) ApiService() {
        fmt.Println("api service")
        fmt.Printf("port : %d \n", ws.Port)
        fmt.Printf("config : %s \n", ws.Config)
        fmt.Printf("logfile : %s \n", ws.LogFile)
        // 启动http服务
    }
    
    // 常驻方式启动
    func (ws *WebService) Service() {
        fmt.Println("service")
        fmt.Printf("config : %s \n", ws.Config)
        fmt.Printf("logfile : %s \n", ws.LogFile)
        // 可以理解成类似Nginx这类服务的启动
    }
    
    

    我们创建Api和Service两个Commands的目录,用于分开执行HTTPService和Service两种模式。

    ApiService:

    在日常工作中,HTTP-Api的试比较常见的获取数据的方式,我们用这个例子来看看在命令行里面如何启动和传递参数的。

    package api
    
    import (
        "fmt"
        "github.com/gzh/webservice"
        "github.com/urfave/cli"
        "os"
    )
    
    var Command = cli.Command{
        Name:    "api",
        Aliases: []string{"web_api", "webApi"}, // 命令别名
        Flags: []cli.Flag{
            // int型参数port,value默认是8080
            cli.IntFlag{
                Name:  "port",
                Value: 8080,
                Usage: "/usr/local/web_service/service api --port=8080",
            },
            // 字符型参数配置文件,默认值为空
            cli.StringFlag{
                Name:  "config",
                Value: "",
                Usage: "/usr/local/web_service/service api --config=/usr/local/web_service/config",
            },
            // 字符型日志文件参数,默认值为空
            cli.StringFlag{
                Name:  "log_file",
                Value: "",
                Usage: "/usr/local/web_service/service api --log_file=/usr/local/web_service/log/web_service.log",
            },
        },
        Action: func(c *cli.Context) error {
    
            var port = c.Int("port")           // 从上下文中获取端口
            var config = c.String("config")    // 从上下文中获取配置文件
            var logFile = c.String("log_file") // 从上下文中获取日志文件
    
            if config == "" {
                _, _ = fmt.Fprintf(os.Stderr, "config is empty!\n")
                os.Exit(100001) // 配置文件错误码
            }
    
            if port <= 0 {
                _, _ = fmt.Fprintf(os.Stderr, "port is empty!\n")
                os.Exit(100002) // 端口错误码
            }
    
            if logFile == "" {
                _, _ = fmt.Fprintf(os.Stderr, "log_file is empty!\n")
                os.Exit(100003) // 日志文件错误码
            }
    
            // 实例webservice,构造函数参数:config,logfile,port
            var api = webservice.NewWebService(config, logFile, port)
            defer api.Freed()
    
            // 启动HTTP-API服务
            api.ApiService()
    
            return nil
        },
    }
    
    

    Service:

    Service类似于Nginx一样,启动后常驻执行的服务,这种在后端中比较多见,下面的示例为Service的启动和传递参数方式。

    package service
    
    import (
        "fmt"
        "github.com/gzh/webservice"
        "github.com/urfave/cli"
        "os"
    )
    
    var Command = cli.Command{
        Name: "service",
        Flags: []cli.Flag{
            // 字符型参数配置,默认值为空
            cli.StringFlag{
                Name:  "config",
                Value: "",
                Usage: "/usr/local/web_service/service api --config=/usr/local/web_service/config",
            },
            // 字符型日志文件参数,默认值为空
            cli.StringFlag{
                Name:  "log_file",
                Value: "",
                Usage: "/usr/local/web_service/service api --log_file=/usr/local/web_service/log/web_service.log",
            },
        },
        Action: func(c *cli.Context) error {
    
            var config = c.String("config")    // 从上下文中获取配置文件
            var logFile = c.String("log_file") // 从上下文中获取日志文件
    
            if config == "" {
                _, _ = fmt.Fprintf(os.Stderr, "config is empty!\n")
                os.Exit(100001) // 配置文件错误码
            }
    
            if logFile == "" {
                _, _ = fmt.Fprintf(os.Stderr, "log_file is empty!\n")
                os.Exit(100003) // 日志文件错误码
            }
    
            // 实例webservice,构造函数参数:config,logfile
            var api = webservice.NewWebService(config, logFile, 0)
            defer api.Freed()
    
            // 启动服务
            api.Service()
    
            return nil
        },
    }
    
    

    完成上面的几个类之后,我们可以创建go_cli.go文件开始我们的编码。主要是实现main函数,里面创建cli实例,配置参数解析相关信息、版本、描述和帮助等信息。

    package main
    
    import (
        "fmt"
        "github.com/gzh/commands/api"
        "github.com/gzh/commands/service"
        "github.com/urfave/cli"
        "os"
    )
    
    func main() {
    
        // 实例化命令行
        app := cli.NewApp()
        // 服务的名称
        app.Name = "WebService"
        // 服务的描述
        app.Description = "Web服务相关描述"
        // 服务的用途描述
        app.Usage = "webservice api --port=8080 --config=path --log_file=/usr/local/webservice/log/go_cli.log"
        // 服务的版本号信息
        app.Version = "1.0.0"
    
        // 初始化多个命令
        app.Commands = []cli.Command{
            // api命令
            api.Command,
            // service命令
            service.Command,
        }
        app.Before = func(context *cli.Context) error {
            // 实现一些逻辑
            return nil
        }
    
        app.After = func(context *cli.Context) error {
            // 实现一些逻辑
            return nil
        }
    
        var err = app.Run(os.Args)
        if err != nil {
            fmt.Println("app run fatal! err : ", err)
        }
    }
    

    运行结果:

    1、编译运行Api示例:

    #go build -o webservice/bin/webservice go_cli.go
    #./webservice/bin/webservice api -port=8080 -config=path -log_file=/usr/local/webservice/log/go_cli.log
    api service
    port : 8080 
    config : path 
    logfile : /usr/local/webservice/log/go_cli.log 
    

    2、编译运行Service示例:

    #go build -o webservice/bin/webservice go_cli.go
    #./webservice/bin/webservice service -config=path -log_file=/usr/local/webservice/log/go_cli.log
    service
    config : path 
    logfile : /usr/local/webservice/log/go_cli.log
    

    3、不传递任何参数的时候,会提示命令会出现HELP信息,运行如下。

    #go build -o webservice/bin/webservice go_cli.go
    #./webservice/bin/webservice
    NAME:
       WebService - webservice api --port=8080 --config=path --log_file=/usr/local/webservice/log/go_cli.log
    
    USAGE:
       go_cli.exe [global options] command [command options] [arguments...]
    
    VERSION:
       1.0.0
    
    DESCRIPTION:
       Web服务相关描述
    
    COMMANDS:
       api
       service
       help, h  Shows a list of commands or help for one command
    
    GLOBAL OPTIONS:
       --help, -h     show help
       --version, -v  print the version
    
    

    总结:

    命令行解析上支持的比较友好,支持的内容比较全面

    使用上方便,快速

    相关文章

      网友评论

          本文标题:Go语言 命令行解析(二)

          本文链接:https://www.haomeiwen.com/subject/ascpvhtx.html