应用程序支持命令行,Python、Golang、C++技术实现

在软件开发中,程序支持命令行的输入,对于代码调试、问题定位起着非常重要的作用,可以大大提升编码的效率。

这篇文章就介绍python、golang、c++三种语言如何实现对命令行的支持。

1、python语言的实现

在python中,最常见的实现命令行的方法是使用内置的【argparse】模块。

导入【argparse】模块:

import argparse

创建argparse对象:

parser = argparse.ArgumentParser()

注册命令行参数:

# 添加参数
parser.add_argument('echo', help='位置参数')
parser.add_argument('-v', '--verbose', help='show version')
parser.add_argument('-b', '--batch', type=int, default=100, help='set batch size')

在使用add_argument函数设置命令行参数时,参数可以有两种形式:

位置参数:比如上面代码的【echo】,这些参数不带【--】前缀,
且都为必须,上面代码示例中位置参数在第一个,程序运行时,必须在第一个位置设定其值,否则将获取不到该参数的值。

选项参数:这些参数通常都带有【--】或者【-】前缀,没有顺序要求,并且可以为选项参数设定默认值。

对于add_argument函数几个重要的参数:

parser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][,choices][, required][, help][, metavar][, dest])

action:可设定四个值:store、store_true、store_false、append,其中store是默认值,即获取参数值,store_true、store_false即带上这个参数时是true或者false,append为可设定多个值,并将参数值放在list当中。   

nargs:指定参数的个数,分别代表如下含义:

'+':表示选项参数可以接受一个或多个参数值。多个参数值将被解析为一个列表。例如,-m 1 4 8 将解析为 args.milestones = [1, 4, 8]。

'*':表示选项参数可以接受零个或多个参数值。多个参数值将被解析为一个列表。例如,-m 15 30 45 将解析为 args.milestones = [15, 30, 45],而不提供 -m 参数将解析为 args.milestones = []。

int:表示选项参数为固定数量的参数值。例如,nargs=2 表示选项参数接受两个参数值。例如,-m 15 30 将解析为 args.milestones = [15, 30]。

解析命令行:

# 解析参数
args = parser.parse_args()

通过命令行参数名称获取参数值:

print("Batch size:", args.batch)

一个完整的代码示例:

import argparse
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    # 添加参数
    parser.add_argument('pos', help='位置参数')
    parser.add_argument('-v', '--verbose', help='enable verbose mode',action="store_true")
    parser.add_argument('-b', '--batch', type=int, default=100, help='set batch size')
    parser.add_argument('-m', '--milestones', nargs='+', required=True, default=15)
    # 解析参数
    args = parser.parse_args()
    # 使用参数
    if args.verbose:
        print("verbose mode is on",args.verbose)
    print("pos参数:", args.pos)
    print("batch size:", args.batch)
    print("milestones:", args.milestones)

2、golang的实现

golang的命令行实现非常的简单,主要使用flag包,设定整型、字符串、bool、时长类型等各种参数,比如增加一个-name参数:

name := flag.String("name", "World", "a name to say hello")

或者写成:

flag.StringVar(&name, "name", "World", "a name to say hello")

两种写法实现的功能完全一样,都是增加了一个字符串参数name,默认值world,参数的帮助信息为a name to say hello。

除了可以设定字符串类型命令参数,也可以设定整型、时长类型、浮点等等类型的参数,一个完整的例子如下:

package main
import (
    "flag"
    "fmt"
)
func main() {
    var enable bool
    name := flag.String("name", "World", "a name to say hello")
    age := flag.Int("age", 35, "age in years")
    flag.BoolVar(&enable, "e", false, "shorthand for enable")
    du := flag.Duration("d", 0, "shorthand for duration")
    flag.Parse()
    fmt.Println("Hello", *name)
    fmt.Println("Age", *age)
    fmt.Println("Enable", enable)
    fmt.Println("Duration", *du)
}

3、c++的实现

在c++中,支持短选项参数以及长选项参数需要使用不同的函数(也可以使用一个函数),短选项参数就是-b、-v,长选项参数--prefix、--version类似这种。

首先对于短选项命令行参数,我们使用函数:

int getopt(int argc, char * const argv[], const char *optstring);
argc:main()函数传递过来的参数的个数
argv:main()函数传递过来的参数的字符串指针数组
optstring:选项字符串,告知 getopt()可以处理哪个选项以及哪个选项需要参数

重点说明下optstring字段:

char*optstring = “ab:c::”;
单个字符a         表示选项a没有参数            格式:-a即可,不加参数
单字符加冒号b:     表示选项b有且必须加参数      格式:-b 100或-b100,但-b=100错
单字符加2个冒号c:: 表示选项c可以有,也可以无     格式:-c200,其它格式错误

对于函数的返回值:

如果选项成功找到,返回选项字母;如果所有命令行选项都解析完毕,返回 -1,如果没有找到对应命令行参数,返回【?】

几个全局全量:

optarg —— 指向当前选项参数(如果有)的指针。
optind —— 再次调用 getopt() 时的下一个 argv指针的索引。
optopt —— 最后一个未知选项。
opterr ­—— 如果不希望getopt()打印出错信息,则只要将全域变量opterr设为0即可。

一般情况下,我们只用到前两个。

#include <iostream>
#include <thread>
#include<getopt.h>
 
int main(int argc, char *argv[]) 
{
    // unsigned int n = std::thread::hardware_concurrency();
    // std::cout << " concurrent threads are supported = " << n << std::endl;
    int opt;
    std::string str = "a::b:c:d";
    while ((opt = getopt(argc, argv, str.data()))!= -1) {  
        printf("opt = %c\t\t", opt);
        printf("optarg = %s\t\t",optarg);
        printf("optind = %d\t\t",optind);
        printf("argv[optind] = %s\n",argv[optind]);
    }
    std::cout << "res:" << opt << std::endl;
}

对于长选项参数,一般使用如下函数:

int getopt_long(int argc, char * const argv[], const char *optstring,
                          const struct option *longopts, int*longindex);

 首先这个函数包含了上面【getopt】函数的全部功能,即支持短选项,又支持长选项参数,对于c++的命令行实现,完全可以用这一个函数。

函数参数说明如下:

optstring   短选项命令行设置,和getopt一致。
longopts    指明了长参数的名称和属性
longindex   如果longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值

struct option结构体:

struct option {
    const char  *name;       /* 参数名称 */
    int          has_arg;    /* 指明是否带有参数 */
    int          *flag;      
    int          val;        
};

int *flag 和 int val:这两个字段用于控制 getopt_long 的返回值和行为。如果 flag 不是 NULL,则 getopt_long 会将 val 的值赋给 *flag,并返回 0,这通常用于不需要返回选项字符的“标志”选项。如果 flag 是 NULL,则 getopt_long 返回 val 的值(对于短选项,这通常是选项字符;对于长选项,这是自定义的值)。

has_arg有三个值可选:

no_argument         表明长选项不带参数,如:--name, --help
required_argument  表明长选项必须带参数,如:--prefix /root或 --prefix=/root
optional_argument  表明长选项的参数是可选的,如:--help或 –prefix=/root,其它都是错误

使用示例:


#include <iostream>
#include <thread>
#include <getopt.h>
 
int main(int argc, char *argv[]) 
{
    unsigned int n = std::thread::hardware_concurrency();
    std::cout << " concurrent threads are supported = " << n << std::endl;
    int opt;
    std::string str = "a::b:c:d";
    static struct option long_options[] =
    {  
        {"reqarg", required_argument,NULL, 'r'},
        {"optarg", optional_argument,NULL, 'o'},
        {"noarg",  no_argument,         NULL,'n'},
        {NULL,     0,                      NULL, 0},
    }; 
    int option_index;
    while((opt = getopt_long(argc,argv,str.data(),long_options,&option_index))!= -1)
    {  
        printf("opt = %c\t\t", opt);
        printf("optarg = %s\t\t",optarg);
        printf("optind = %d\t\t",optind);
        printf("argv[optind] =%s\t\t", argv[optind]);
        printf("option_index = %d\n",option_index);
    }  
}

编译上述代码并运行:

 好了,三种语言的命令行支持就全部实现了,需要的同学可以直接拿去用,全部代码都在这里:

https://github.com/liupengh3c/career/tree/main/cmd

欢迎小伙伴们关注、交流,也非常欢迎大家大家关注公众号微信沟通,知无不言~~~~~~~~~~。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值