C语言中命令行参数处理

2022-06-16 09:39:47

应用场景

命令行参数有不同的样式。

# 短选项与长选项ls -a# 短线后面跟选项,选项没有参数ls -alh# 不带参数的选项可用连写,不分先后顺序ls --all# 双短线的长选项,和-a是相同的功能# 选项后面是否跟参数ls -a# 不带参数ls --block-size=SIZE# 带参数ls --color[=WHEN]# 参数可选,选项和参数之间没有空格

ls使用getopt_long()函数实现上面功能。

staticstructoptionconst long_options[]={{"all", no_argument,NULL,'a'},{"escape", no_argument,NULL,'b'},...{"context", no_argument,0,'Z'},{"author", no_argument,NULL, AUTHOR_OPTION},{GETOPT_HELP_OPTION_DECL},{GETOPT_VERSION_OPTION_DECL},{NULL,0,NULL,0}};int c=getopt_long(argc, argv,"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1",long_options,&oi);

可以看到命令行选项有两种样式(两者不等价):long_options[]"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1"
(对于--color长选项来说,它没有对应的短选项)

long_options[]使用的option结构体如下:

structoption{constchar*name;// 长选项名int has_arg;// 选项是否带参数:不带参数,带参数,参数可选int*flag;// 当flag等于NULL,getopt_long返回valint val;// val 可以设置成长选项名的第一个字母};

长选项转换成短选项。

constchar*optstring_from_long_options(conststructoption*opt){// 将长参数转换成短参数// "AB:C::"表示:A后面没有参数;B后面有参数;C后面可以有参数,也可以没有,有的话必须紧跟选项staticchar optstring[256]={0};char*osp= optstring;for(; opt->name!=NULL; opt++){if(opt->flag==0&& opt->val>='A'&& opt->val<='z'){*osp++= opt->val;switch(opt->has_arg){case optional_argument:*osp++=':';*osp++=':';break;case required_argument:*osp++=':';break;default:break;}}}return optstring;}

实践

下面的代码改自fuzznetlink.c

需求:打印文字情感logo。

  • 一个选项(无参数),用以确定情感文字类型。
  • 一个选项(带参数),用以确定打印一类情感文字的个数。
  • 一个选项(可选参数),不带参数时随机打印一个情感文字,带参数时打印指定个数的情感文字。
➜  tree.
├── comm.h
├── logo.cpp
├── long_options.cpp
└── Makefile0 directories,4 files

其他代码见仓库。下面为命令行参数处理代码。

#include<getopt.h>#include<iostream>#include<vector>#include<string>#include"comm.h"

using namespace std;structstate{int smile_nums=0;int cry_nums=0;int tired_nums=0;int nums=0;int kinds=3;};staticvoidusage(constchar*command){// C语言中连续的用""引起的字符串常量,会默认合并为一个常量字符串fprintf(stderr,"Usage:\n""\n""   %s [option]\n""\n""Options;\n""\n""   -s --smile        Print smile logo\n""   -c --cry          Print cry logo\n""   -t --tired        Print tired logo\n""   -n --nums         nums logos are printed\n""   -r --rand         rand(choice) output logo\n""\n",
    command);}constchar*optstring_from_long_options(conststructoption*opt){// 将长参数转换成短参数// "AB:C::"表示:A后面没有参数;B后面有参数;C后面可以有参数,也可以没有,有的话必须紧跟选项staticchar optstring[256]={0};char*osp= optstring;for(; opt->name!=NULL; opt++){if(opt->flag==0&& opt->val>='A'&& opt->val<='z'){*osp++= opt->val;switch(opt->has_arg){case optional_argument:*osp++=':';*osp++=':';break;case required_argument:*osp++=':';break;default:break;}}}return optstring;}intmain(int argc,char**argv){staticstructoption long_options[]={{"smile",no_argument,NULL,'s'},{"cry",no_argument,NULL,'c'},{"tired",no_argument,NULL,'t'},{"nums",required_argument,NULL,'n'},{"rand",optional_argument,NULL,'r'},{NULL,0,0,0}};constchar*optstring=optstring_from_long_options(long_options);structstate st;int i=0, n=0;while(1){int option_index=0;int arg=getopt_long(argc,argv,optstring,long_options,&option_index);if(arg==-1)break;switch(arg){case0:fprintf(stderr,"Unknow option :%s", long_options[option_index].name);exit(-1);break;case's':
            st.smile_nums=1;break;case'c':
            st.cry_nums=1;break;case't':
            st.tired_nums=1;break;case'n':
            st.nums=atoi(optarg);break;case'r':// 随机生成optarg个相同的表情if(optarg)
                n=atoi(optarg);else
                n=1;srand(time(NULL));
            i=rand()%st.kinds;if(i==0)
                st.smile_nums= n;elseif(i==1)
                st.cry_nums= n;else
                st.tired_nums= n;break;default:fprintf(stderr,"Unknow option :%s", long_options[option_index].name);exit(-1);break;}}if(st.nums!=0){if(st.smile_nums) st.smile_nums= st.nums;if(st.cry_nums) st.cry_nums= st.nums;if(st.tired_nums) st.tired_nums= st.nums;}// 根据读取的参数,绘制表情for(int i=0; i<st.smile_nums; i++)print_logo(smile_str);for(int i=0; i<st.cry_nums; i++)print_logo(cry_str);for(int i=0; i<st.tired_nums; i++)print_logo(tired_nums);return0;}

执行结果如下:

./long_options --tired
  _   _              _||(_)||||_ _ _ __ ___  __||| __||'__/ _ \/ _`|||_||||  __/(_||\__|_|_|\___|\__,_|
                       

./long_options -c -n2
                  
  / __|'__| | | |
 | (__| |  | |_| |
  \___|_|   \__, |
             __/ |
            |___/ 
                  
                  
  / __| '__|||||(__||||_||\___|_|\__,|
             __/||___/ 


./long_options -r2    
                _ _(_)|     
  ___ _ __ ___  _|| ___ 
 / __| '_` _ \| | |/ _ \
 \__ \ | | | | | | |  __/
 |___/_| |_| |_|_|_|\___|
                         
                         
                _ _      
               (_) |     
  ___ _ __ ___  _| | ___ 
 / __| '_` _\|||/ _\\__\|||||||  __/|___/_||_||_|_|_|\___|


 ./long_options -st
                _ _(_)|     
  ___ _ __ ___  _|| ___ 
 / __| '_` _\|||/ _\\__\|||||||  __/|___/_||_||_|_|_|\___|
                         
                         
  _   _              _||(_)||||_ _ _ __ ___  __||| __|| '__/ _\/ _`|||_||||  __/(_||\__|_|_|\___|\__,_|

相关链接

getopt(3) — Linux manual page

Linux下getopt_long函数的使用

附录

其他代码

头文件:comm.h

#ifndef COMM_H
#define COMM_H

#include <vector>
#include <string>
#include <iostream>

// logo相关的变量声明和函数
extern const std::vector<std::string> smile_str;
extern const std::vector<std::string> cry_str;
extern const std::vector<std::string> tired_nums;
void print_logo(const std::vector<std::string> &logo);

#endif

logo相关函数和数据结构。

#include <vector>
#include <string>
#include <iostream>

#include "comm.h"

const std::vector<std::string> smile_str = {
    "                _ _      ",
    "               (_) |     ",
    "  ___ _ __ ___  _| | ___ ",
    " / __| '_ ` _ \\| | |/ _ \\",
    " \\__ \\ | | | | | | |  __/",
    " |___/_| |_| |_|_|_|\\___|",
    "                         ",
    "                         "
};

const std::vector<std::string> cry_str = {
    "                  ",
    "  / __| '__| | | |",
    " | (__| |  | |_| |",
    "  \\___|_|   \\__, |",
    "             __/ |",
    "            |___/ ",
    "                  "
};

const std::vector<std::string> tired_nums = {
    "  _   _              _ ",
    " | | (_)            | |",
    " | |_ _ _ __ ___  __| |",
    " | __| | '__/ _ \\/ _` |",
    " | |_| | | |  __/ (_| |",
    "  \\__|_|_|  \\___|\\__,_|",
    "                       ",
    "                       "
};

void print_logo(const std::vector<std::string> &logo){
    int n = logo.size();
    for(int i=0; i<n; i++)
        std::cout<<logo[i]<<std::endl;
}

编译过程:makefile

all:long_options

long_options:long_options.cpp logo.cpp
	g++ -o $@ $^ -I .

clean:
	rm -f long_options

非选项参数处理

下面的SOURCEDEST为非选项参数。本篇没有介绍,非选项参数的处理。

cp[OPTION]...[-T] SOURCE DEST

使用optind变量很容易处理。参见示例:打印参数

  • 作者:大1234草
  • 原文链接:https://da1234cao.blog.csdn.net/article/details/122106295
    更新时间:2022-06-16 09:39:47