命令行启动服务的方式,在后端使用非常广泛,如果有写过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\n", argc);
printf("执行程序的名称:%s\n", argv[0]); int i = 1; // 从下标1开始获取,因为0代表的是程序名称 while(i < argc)
{
// 循环打印每个命令行的参数
printf("%s\n", 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\n")
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 \n", tcp_port)
fmt.Printf("service port : %d \n", *port)
fmt.Printf("service config : %s \n", *config)
fmt.Printf("service logfile : %s \n", *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还不能够解析复杂结构的启动参数。

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

Go语言 命令行解析(一)的更多相关文章

  1. 【嵌入式开发】C语言 命令行参数 函数指针 gdb调试

    . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21551397 | http://www.hanshul ...

  2. .NET:命令行解析器介绍

    背景 经常需要开发一下小工具,之前都是自己解析命令行参数,接触过动态语言社区以后,发现命令行解析有特定的模式和框架可以利用,本文介绍一个 .NET 平台的类库. 示例 需求 拷贝文件,如:CopyFi ...

  3. C语言 命令行参数 函数指针 gdb调试

    . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21551397 | http://www.hanshul ...

  4. Python命令行解析argparse常用语法使用简介

    查看原文:http://www.sijitao.net/2000.html python中的命令行解析最简单最原始的方法是使用sys.argv来实现,更高级的可以使用argparse这个模块.argp ...

  5. Noah的学习笔记之Python篇:命令行解析

    Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang  (http://www.cnblogs.com/noahzn/) ...

  6. python命令行解析工具argparse模块【1】

    argpaser是python中很好用的一个命令行解析模块,使用它我们可以很方便的创建用户友好型命令行程序.而且argparse会自动生成帮助信息和错误信息. 一.示例 例如下面的例子,从命令行中获取 ...

  7. python实现命令行解析的argparse的使用

    参考https://docs.python.org/3.6/library/argparse.html argparse模块使编写用户友好的命令行界面变得很容易.程序定义了它需要什么参数,argpar ...

  8. 使用命令行解析php文件

    使用命令行解析php文件,这样可以调用Log4PHP库中的一些demo,因为默认的输出使用命令行作为输出. 建一个bat文件: echo 以下是使用命令行解析php文件 C:\xampp\php\ph ...

  9. 『Argparse』命令行解析

    一.基本用法 Python标准库推荐使用的命令行解析模块argparse 还有其他两个模块实现这一功能,getopt(等同于C语言中的getopt())和弃用的optparse.因为argparse是 ...

随机推荐

  1. C++ 深拷贝和浅拷贝详解

    前言 在对象拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型成员变量,调用其相应类型的拷贝构造函数. 位拷贝( ...

  2. 试译 Understanding Delta-Sigma Modulators

         接触Σ-Δ调制的时候发现国内有关的资料比较匮乏,因为缺乏了解还有一些人把其中的原理吹得神乎其神难以理解.其实Σ-Δ调制的原理是很简单.逻辑上很自然的,可以定性理解成传统ADC/DAC量化的是 ...

  3. 【Excel使用技巧】vlookup函数

    背景 前不久开发了一个运营小工具,运营人员上传一个id的列表,即可导出对应id的额外数据.需求本身不复杂,很快就开发完了,但上线后,运营反馈了一个问题,导出后的数据跟导出之前的数据顺序不一致. 经过沟 ...

  4. CMD 基础命令

    基本命令 1.编译.java文件成.class:找到文件所在路径 --> java -d . 文件名称.java --> javac -d . 文件名称.java : 2.ping URL ...

  5. Xamarin.Forms读取并展示Android和iOS通讯录 - TerminalMACS客户端

    Xamarin.Forms读取并展示Android和iOS通讯录 - TerminalMACS客户端 本文同步更新地址: https://dotnet9.com/11520.html https:// ...

  6. layer弹层插件

      // 使用前需要引入jquery的支持,链接如下:   https://blog-static.cnblogs.com/files/liguanlong/jquery1.9.1.min.js    ...

  7. effective-java学习笔记---使用枚举类型替代整型常量34

    1.要将数据与枚举常量相关联,请声明实例属性并编写一个构造方法,构造方法带有数据并将数据保存在属性中. // Enum type with data and behavior public enum ...

  8. postman设置全局变量及参数化

    笔者第一次记录使用过程,仅供参考 测试过程中接口的前缀都是一样的,所以我们可以将这个前缀作为全局变量来使用 首先,打开postman点击这里的小齿轮设置 在这里就可以进行变量的一个添加,添加好之后记住 ...

  9. 让vscode支持WePY框架 *.wpy

    WePY框架的.wpy 文件在微信开发者工具中无法打开,这里使用vscode 打开,并安装vetur 和vetur-wepy  插件即可

  10. mybatis 入门基础

    一.Mybatis介绍 MyBatis是一款一流的支持自定义SQL.存储过程和高级映射的持久化框架.MyBatis几乎消除了所有的JDBC代码,也基本不需要手工去设置参数和获取检索结果.MyBatis ...