• Go语言 命令行解析(一)


    命令行启动服务的方式,在后端使用非常广泛,如果有写过C语言的同学相信不难理解这一点!在C语言中,我们可以根据argc和argv来获取和解析命令行的参数,从而通过不同的参数调取不同的方法,同时也可以用Usage来打印帮助信息了。

    那么开始今天的话题之前,我们回顾一下在C语言中是如何解析传递的参数的。

    示例代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    // argc 为int型
    // argv 为char指针数组,元素个数是argc,存放的是指向每一个参数的指针
    int main(int argc, char *argv[])
    {
    
        printf("命令行参数个数: %d
    ", argc);
        printf("执行程序的名称:%s
    ", argv[0]);
    
        int i = 1; // 从下标1开始获取,因为0代表的是程序名称
    
        while(i < argc)
        {
            // 循环打印每个命令行的参数
            printf("%s
    ", argv[i]);
            i++;
        }
    
        return 0;
    }

    编译运行:

    #gcc c_cli.c -o c_cli
    ./c_cli /usr/local/service/config /usr/local/service/log/service.log                   
    命令行参数个数: 3
    执行程序的名称:./c_cli
    /usr/local/service/config
    /usr/local/service/log/service.log

    看完上面的例子,其实我们可以发现,上例中是C语言自带的参数解析,对于简单的参数构成还是可以使用的。下面我们再看一下Go语言os标准库的实现。

    示例代码:

    package main
    
    import (
    	"fmt"
    	"os"
    )
    
    func main() {
    
    	var args = os.Args
    	fmt.Println(args)
    
    	return
    }
    

    编译执行:

    #go build go_flag.go
    #./go_flag /usr/local/service/config /usr/local/service/log/service.log
    [./go_flag /usr/local/service/config /usr/local/service/log/service.log]

    上例中,我们可以看到os.Args返回一个数组,数组里面是我们命令行执行时,所传递的参数和程序名称。os自带的参数获取,对于简单的参数来说还能使用,如果参数复杂的情况下,那么解析起来就比较费劲的。这个时候,我们可以选择Go语言的flag标准库来帮我们处理命令行解析工作。

    Flag包:https://golang.org/pkg/flag/

    是Go语言提供的一个标准库,能够较为方便和灵活的解析命令行传递的参数。

    flag有两种方式:

    1、flag.Type,其中Type可以是:int、string、bool,float等类型,返回指针类型。

    var port = flag.Int("port", 0, "相关描述")

    参数1:flag的名称

    参数2:flag的值,上例中默认值是0

    参数3:flag的描述

    2、flag.TypeVar,将类型绑定到一个变量上。

    var port int
    flag.IntVar(&port, "port", 0, "相关描述")

    参数1:flag的值

    参数2:flag的名称

    参数3:flag的值,上例中默认值是0

    参数4:flag的描述

    示例代码:

    package main
    
    import (
    	"flag"
    	"fmt"
    	"os"
    )
    
    var (
    	// 定义一个tcp端口号
    	tcp_port int
    
    	// flag.Type(Name为Flag的名字,Value是Flag的值,Usage是Flag的提示信息)
    	port    = flag.Int("port", 0, "服务端口设置参数为:-port=80")
    	config  = flag.String("config", "", "配置文件配置参数为:-config=/usr/local/service/config")
    	logFile = flag.String("logfile", "", "日志文件配置参数为:-logfile=/usr/local/service/log/service.log")
    	// flag.Type返回的是指针类型,所以获取值为"*变量"
    
    )
    
    func init() {
    	flag.IntVar(&tcp_port, "tcp_port", 0, "TCP服务端口描述: -tcp_port=2001")
    	flag.Usage = func() {
    		_, _ = fmt.Fprint(os.Stderr,
    			"cli : go_flag -port=8080 -config=/usr/local/service/config "+
    				"-logfile=/usr/local/service/log/service.log -tcp_port=2001
    ")
    		flag.PrintDefaults()
    	}
    
    	flag.Parse()
    }
    
    func main() {
    
    	if *port <= 0 {
    		flag.PrintDefaults()
    		os.Exit(1)
    	}
    
    	if tcp_port <= 0 {
    		flag.PrintDefaults()
    		os.Exit(1)
    	}
    
    	if *config == "" {
    		flag.PrintDefaults()
    		os.Exit(2)
    	}
    
    	if *logFile == "" {
    		flag.PrintDefaults()
    		os.Exit(3)
    	}
    
    	fmt.Printf("service tcp port : %d 
    ", tcp_port)
    	fmt.Printf("service port : %d 
    ", *port)
    	fmt.Printf("service config : %s 
    ", *config)
    	fmt.Printf("service logfile : %s 
    ", *logFile)
    	return
    }
    

    运行结果:

    #go build go_flag.go
    #./go_flag 
      -config string
            配置文件配置参数为:-config=/usr/local/service/config
      -logfile string
            日志文件配置参数为:-logfile=/usr/local/service/log/service.log
      -port int
            服务端口设置参数为:-port=80
      -tcp_port int
            TCP服务端口描述: -tcp_port=2001
    
    #./go_flag -port 8090 -config=/usr/local/service/config -logfile= /usr/local/service/log/service.log -tcp_port=2001
    service tcp port : 2001 
    service port : 8090 
    service config : /usr/local/service/config 
    service logfile : /usr/local/service/log/service.log 

    查看帮助:

    #./go_flag -h
    cli : go_flag -port=8080 -config=/usr/local/service/config -logfile=/usr/local/service/log/service.log
      -config string
            配置文件配置参数为:-config=/usr/local/service/config
      -logfile string
            日志文件配置参数为:-logfile=/usr/local/service/log/service.log
      -port int
            服务端口设置参数为:-port=80
      -tcp_port int
            TCP服务端口描述: -tcp_port=2001

    Flag语法:

    • -flag 只支持bool参数
    • -flag=p 
    • -flag p bool类型不能使用,当p为false时会引起歧义

    Flag解析:

    parseOne()函数来处理-flag=value的,如果处理成功后,会将flag存储到FlagSet.actucal map[string]*Flag中。

    flag.Parse()函数来解析命令行中的参数中定义的flag,该方法遇到第一个非flag的命令方法就中止。

    1、non-flag的时候,会终止解析工作。

    2、连续两个“-”的时候,会终止解析工作。

    然后,再看我们传递错误的参数的返回情况。

    #./go_flag -a=b
    flag provided but not defined: -a
    cli : go_flag -port=8080 -config=/usr/local/service/config -logfile=/usr/local/service/log/service.log
      -config string
            配置文件配置参数为:-config=/usr/local/service/config
      -logfile string
            日志文件配置参数为:-logfile=/usr/local/service/log/service.log
      -port int
            服务端口设置参数为:-port=80
      -tcp_port int
            TCP服务端口描述: -tcp_port=2001

    跟踪到代码中可以看到如图:

    从上例可见,其实flag并没有非常强大,下一章节会介绍一个更强大的命令行解析工具。

    总结:

    1. os标准库提供的解析方法,能够解析简单的命令行参数。
    2. flag能够解析约定好的常规按照-flag传递的命令行参数,有帮助信息。
    3. os和flag还不能够解析复杂结构的启动参数。

    喜欢的话,可以关注公众号

  • 相关阅读:
    google说 老子 = I !
    昨日种种死 今日种种生
    设定Access数据库自增长字段初始值
    [c路历程]品品数组这杯茶
    爱上位运算
    .Net中的委托
    Jquery css函数用法(判断标签是否拥有某属性)
    记录几条简单的正则表达式
    ASP.NET MVC中DropDownList的使用
    C#如何获取object对象的属性值
  • 原文地址:https://www.cnblogs.com/guichenglin/p/12716433.html
Copyright © 2020-2023  润新知