命令行参数解析函数 getopt、getopt_long

article/2025/10/20 3:53:18

getopt 函数在头文件 <unistd.h> 中,它可以解析我们传入的命令行参数。 可以实现类似 gcc -orm -rf 等命令。

man 3 getopt 。在线版:http://man.he.net/?topic=getopt&section=3

       #include <unistd.h>int getopt(int argc, char * const argv[],const char *optstring);extern char *optarg;extern int optind, opterr, optopt;#include <getopt.h>int getopt_long(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);int getopt_long_only(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);Feature Test Macro Requirements for glibc (see feature_test_macros(7)):getopt(): _POSIX_C_SOURCE >= 2 || _XOPEN_SOURCEgetopt_long(), getopt_long_only(): _GNU_SOURCE

使用说明:getopt函数在main()函数中argv携带的参数中进行匹配,以-为标记。

  • 短参数:-a-ab-a -b 。其中短参数如果有值的话,可以使用空格分隔,也可以写在一起。例如 head -n10 等效 head -n10
  • 长参数 :--version 。长参数后面如果携带值,可以使用空格分隔,或使用=链接。

getopt

#include <unistd.h>int getopt(int argc, char * const argv[],const char *optstring);extern char *optarg;
extern int optind, opterr, optopt;

对于 getopt() 函数而言,argc和argv参数通常直接从main()的参数直接传递而来。optstring是预处理的可选选项组成的字符串。

optstring:
getopt函数会在argv中进行字符匹配,匹配所使用的参数集合是定义在optstring 中的字母。

  • 如果选项字符串里的字母后接着冒号":",则表示还有相关的参数,全域变量optarg 即会指向此额外参数。
  • 如果getopt()找不到符合的参数则会印出错信息,并将全域变量optopt 设为"?"字符, 如果不希望getopt()印出错信息,则需要将全域变量opterr 设为0 。
  • 如果后面两个冒号,表示后面可以有参数也可以没有参数,但是如果有参数,参数和选项之间不能有空格

当给定getopt()命令参数的数量 (argc)、指向这些参数的数组 (argv) 和选项字串 (optstring) 后,getopt() 将返回第一个选项,并设置一些全局变量。使用相同的参数再次调用该函数时,它将返回下一个选项,并设置相应的全局变量。如果不再有可识别的选项,将返回 -1,此任务就完成了。

getopt() 所设置的全局变量包括:

  • char *optarg
    当前选项参数字串(如果有)。
  • int optind
    argv的当前索引值。当getopt()在while循环中使用时,循环结束后,剩下的字串视为操作数,在argv[optind]至argv[argc-1]中可以找到。
  • int opterr
    这个变量非零时,getopt()函数为“无效选项”和“缺少参数选项,并输出其错误信息。
  • int optopt
    当发现无效选项字符之时,getopt()函数或返回’?‘字符,或返回’:'字符,并且optopt包含了所发现的无效选项字符。

需要知道的是,getopts会默认将argv排列,使得选项在前,而非选项的参数放在最后。这样当getopts读取完所有的选项以后,optind会指向非选项的参数。

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main (int argc, char **argv)
{for(int i = 0; i < argc; ++i)printf("%s ",argv[i]);printf("\n");int c;while( -1 != (c = getopt (argc, argv, "abc:"))){;}for(int i = 0; i < argc; ++i)printf("%s ",argv[i]);printf("\n");return 0;
}

在这里插入图片描述

示例程序:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int
main (int argc, char **argv)
{int aflag = 0;	// 如果输入 -aint bflag = 0;	// 如果输入-bchar *cvalue = NULL;	// 输入 -c xxxx,保存c选项对应的值int index;int c;opterr = 0;	// 错误标记:标记“无效选项”和“缺少参数选项”while ((c = getopt (argc, argv, "abc:")) != -1)switch (c){case 'a':aflag = 1;break;case 'b':bflag = 1;break;case 'c':cvalue = optarg;	// 接收c选项的对应的值,如果没有值则下一次getopt返回‘?’break;case '?':if (optopt == 'c')fprintf (stderr, "Option -%c requires an argument.\n", optopt);else if (isprint (optopt))	// 检测一个字符是否是可打印字符fprintf (stderr, "Unknown option `-%c'.\n", optopt);else						// 如果不可打印,输出其ascii值fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt);return 1;default:abort ();}// getopt 匹配完毕,输出参数获取情况printf ("aflag = %d, bflag = %d, cvalue = %s\n",aflag, bflag, cvalue);// 将剩余的没有匹配到的参数打印出来for (index = optind; index < argc; index++)printf ("Non-option argument %s\n", argv[index]);return 0;
}

编译并执行:

gcc -Wall -o opt opt.c
./opt

1.无参、-a、-b、-ab、-a -b
在这里插入图片描述
2.使用c参数。参数c在代码中设置为 c: 需要对应数值。
在这里插入图片描述
3.关于参数对应的值,我们可以将他们紧挨着一起写,也可以使用空格分隔开。同时我们发现如果多次调用 -c 参数,cvalue的值会被覆盖(每次optarg匹配一个值,为了避免被覆盖我们可以使用数据结构将其保存起来,例如 st.push(optacg))。
在这里插入图片描述

全部执行情况:

% ./opt
aflag = 0, bflag = 0, cvalue = (null)% ./opt -a -b
aflag = 1, bflag = 1, cvalue = (null)% ./opt -ab
aflag = 1, bflag = 1, cvalue = (null)% ./opt -c foo
aflag = 0, bflag = 0, cvalue = foo% ./opt -cfoo
aflag = 0, bflag = 0, cvalue = foo% ./opt arg1
aflag = 0, bflag = 0, cvalue = (null)
Non-option argument arg1% ./opt -a arg1
aflag = 1, bflag = 0, cvalue = (null)
Non-option argument arg1% ./opt -c foo arg1
aflag = 0, bflag = 0, cvalue = foo
Non-option argument arg1% ./opt -a -- -b
aflag = 1, bflag = 0, cvalue = (null)
Non-option argument -b% ./opt -a -
aflag = 1, bflag = 0, cvalue = (null)
Non-option argument -

示例2:写一个程序,要求从命令行传入数据,将其累加结果输出到屏幕上。

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;// 对vector元素求和
int add(vector<int>& vec)
{int sum = 0;for(const int & v : vec){sum += v;}return sum;
}int main(int argc, char* argv[])
{if(argc <= 1){cout << "please input list-nums. \n ./add  1 2 3 4" << endl;return 0;}vector<int> vec;for(int i = 0; i < argc; ++i){if(strspn(argv[i], "0123456789") != strlen(argv[i]))continue;               // 只接受数字int num = stoi(argv[i]);        // 将‘1’转为1vec.push_back(num);             // 添加到vec中}if(!vec.empty()){cout << "total sum = " << add(vec) << endl;}return 0;
}

在这里插入图片描述
如果将它改造成,接收以 - 开头的参数,则代码应该这样写。

#include <iostream>
#include <unistd.h>
#include <cstring>
#include <vector>
using namespace std;
// 帮助字符串,提示该程序的参数
const char* helpstr ={R"(Help:Example "-l":   ./opt -l 1 2 3 4 5 6Output:         total sum = 21Example "-v":	./opt -l 1,2,3,4,5,6Output:         nums:{ 1, 2, 3, 4, 5, 6 }total sum = 21)"
};
// 从命令行接收数据,print 参数表示是否在录入数据时打印到屏幕上
void input(vector<int>& vec, int argc, char* argv[], bool print = false)
{if(print) cout << "nums:{ " ;for(int i = optind - 1; i < argc; ++i){if(strspn(argv[i], "0123456789") != strlen(argv[i]))continue;               // 只接受数字int num = stoi(argv[i]);        // 将‘1’转为1vec.push_back(num);             // 添加到vec中if(print) cout << num << ", ";  // 根据参数决定是否打印}if(print) cout << "\b\b }" << endl;}// 对vector元素求和
int add(vector<int>& vec)
{int sum = 0;for(const int & v : vec){sum += v;}return sum;
}int main(int argc, char* argv[])
{if(argc <= 1){cout << "please input list-nums. \n ./opt -l 1 2 3 4" << endl;return 0;}vector<int> vec;bool list_flag = false;	// 是否输入了 -lbool view_flag = false;	// 是否输入了 -vint opt;	// 接收命令行 `-` 开头的参数while ((opt = getopt (argc, argv, "hvl::")) != -1)switch(opt){case 'h':cout << helpstr << endl;break;case 'v':       // 显示输入的元素,即vec的元素view_flag = true;break;case 'l':       // 使用 ./opt -l 1 2 3 4 5 6 的方式输入元素list_flag = true;break;case '?':case ':':default:break;}if(list_flag){	// 如果使用了 -l 参数,计算求和结果input(vec, argc, argv, view_flag);cout << "total sum = " << add(vec) << endl;}return 0;
}

-h、-l、-v参数展示
在这里插入图片描述

getopt_long

#include <getopt.h>int getopt_long(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);int getopt_long_only(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);

getopt long()函数的工作原理与getopt()类似,只是它也接受以两个减号开始的长选项。(如果程序只接受长选项,那么optstring应该指定为空字符串(""),而不是NULL。)

如果缩写是唯一的,或者与某个已定义的选项精确匹配,则长选项名称可以缩写。长选项可以带有一个形式为 --arg=param--arg param 的参数。

Longopts是指向<getopt.h>中声明的struct option数组的第一个元素的指针

struct option {const char *name;int         has_arg;int        *flag;int         val;
};

不同字段的含义是:

  • name :是长选项的名称。

  • has_arg :如果选项不带参数,则使用 no_argument(或0);
    如果选项需要参数,则使用required_argument(或1);
    如果该选项带有可选参数,则使用optional_argument(或2)

  • flag :Flag指定如何返回长选项的结果。
    如果flag为NULL,那么getopt_long()返回val。(例如,调用程序可能将val设置为等效的短选项字符)。
    否则,getopt_long()返回0,并且flag指向一个变量,如果找到该选项则将该变量设置为val,但如果没有找到该选项则保持不变。

  • val : 是要返回的值,或装入由标志所指向的变量中的值

注意:

  • 数组的最后一个元素必须填充零。
  • 如果longindex不是NULL,它指向一个变量,该变量被设置为long选项相对于longopts的索引。

getopt_long_only()类似于getopt_long(),但是’-‘和"–"可以表示一个长选项。如果以’-’(而不是"–")开头的选项不匹配长选项,但匹配短选项,它将被解析为短选项。

#include  <stdio.h>      /* for printf */ 
#include <stdlib.h>    /* for exit */ 
#include <getopt.h>int main(int argc, char **argv) {int c;int digit_optind = 0;while (1) {int this_option_optind = optind ? optind : 1;int option_index = 0;static struct option long_options[] = {{"add",     required_argument, 0,  0 },	// 需要参数,flag=null,则返回val的值0{"append",  no_argument,       0,  0 },	// 不需要参数,返回val的值0{"delete",  required_argument, 0,  0 },	// 需要参数,返回val的值0{"verbose", no_argument,       0,  0 },	// 不需要参数,返回val的值0{"create",  required_argument, 0, 'c'},	// 需要参数,返回val的值 ‘c’ 。等效-c选项{"file",    required_argument, 0,  0 },	// 需要参数,返回val的值 0{0,         0,                 0,  0 }	// 最后一行元素填充0};c = getopt_long(argc, argv, "abc:d:012",long_options, &option_index);if (c == -1)	// 无参数可匹配了break;switch (c) {case 0:	// 本例中接收长参数(-create参数除外)printf("option %s", long_options[option_index].name);if (optarg)printf(" with arg %s", optarg);printf("\n");break;case '0':case '1':case '2':if (digit_optind != 0 && digit_optind != this_option_optind)printf("digits occur in two different argv-elements.\n");digit_optind = this_option_optind;printf("option %c\n", c);break;case 'a':printf("option a\n");break;case 'b':printf("option b\n");break;case 'c':printf("option c with value '%s'\n", optarg);break;case 'd':printf("option d with value '%s'\n", optarg);break;case '?':break;default:printf("?? getopt returned character code 0%o ??\n", c);}}if (optind < argc) {printf("non-option ARGV-elements: ");while (optind < argc)printf("%s ", argv[optind++]);printf("\n");}exit(EXIT_SUCCESS); 
}

1.接收短参数
在这里插入图片描述
2.接收带值的短参
在这里插入图片描述
3.长参数映射到 -0 选项。注意,长参数设定为 required_argument 的需要指定一个参数值,使用“=”连接或空格都可以。
在这里插入图片描述
4.getopt_long也可以识别长选项的简写,但需要保证简写可以唯一标识某个长选项。例如 --hello 与 --help 这两个长参数无法通过 --he 或 --hel 区分。
在这里插入图片描述

示例2:引用自:https://www.jianshu.com/p/e46a37d7b776

#include <unistd.h>
#include <stdio.h>
#include <getopt.h>int main(int argc, char **argv)
{int opt, lopt, loidx;const char *optstring = "ab:c::d:t";const struct option long_options[] ={	// 使用--help等参数后,getopt_long()函数返回0,同时将val对应的值赋值到lopt变量中{"help", no_argument, &lopt, 1},		// getopt_long()返回0,lopt被赋值为1{"version", no_argument, &lopt, 2},		// ..{"infile", required_argument, &lopt, 3},{"outfile", required_argument, &lopt, 4},{"logfile", optional_argument, &lopt, 5},{"tttt", no_argument, 0 , 't'},	// 等价于使用 -t 选项{0, 0, 0, 0}};while((opt = getopt_long(argc, argv, optstring, long_options, &loidx)) != -1){if(opt == 0)	// long_options[x].flag非空时,getopt_long()函数返回0opt = lopt;	// long_options[x].flag所执行的变量被赋值为long_options[x].val switch(opt){case 'a':printf("opt a==%c\n", opt);break;case 'b':printf("opt b==%c, arg: %s\n", opt, optarg);break;case 'c':printf("opt c==%c, arg: %s\n", opt, optarg);break;case 'd':printf("opt d==%c, arg: %s\n", opt, optarg);break;case 't':printf("opt t==%c\n", opt);printf("\"-t\" equivalent \"--tttt\"\n");break;case 1:printf("opt help==%d\n", opt);break;case 2:printf("opt version==%d\n", opt);break;case 3:printf("opt infile==%d arg: %s\n", opt, optarg);break;case 4:printf("opt outfile==%d arg: %s\n", opt, optarg);break;case 5:printf("opt logfile==%d arg: %s\n", opt, optarg);break;default:printf("error opt %c", opt);return -1;}}return 0;
}$ g++ -o test test.cpp
$ ./test --help
opt help==1
$ ./test --help --infile
pt help==1
./test: option '--infile' requires an argument
error opt x
$ ./test --help --infile 123
opt help==1
opt infile==3 arg: 123

1.普通短参数
在这里插入图片描述
2.长参数 -tttt 和 与之等效的短参数 -t
在这里插入图片描述
3.长参数
在这里插入图片描述


http://chatgpt.dhexx.cn/article/XpKA7wXs.shtml

相关文章

C/C++ 命令解析:getopt 方法详解和使用示例

一、简介 getopt() 方法是用来分析命令行参数的&#xff0c;该方法由 Unix 标准库提供&#xff0c;包含在 <unistd.h> 头文件中。 二、定义 int getopt(int argc, char * const argv[], const char *optstring);extern char *optarg; extern int optind, opterr, optop…

*args和**kwargs

*args和**kwargs的区别 首先*args和**kwargs的区别主要是*和**的区别&#xff0c;与变量名args和kwargs无关&#xff0c;也可以命名成*cat和**dog&#xff1b;*args接收不带变量名的变量&#xff0c;**kwargs接收带变量名的变量。*args和**kwargs可以共同使用&#xff0c;但是顺…

python中argparse模块关于 parse_args() 函数详解(全)

目录 前言1. 函数讲解2. 基本用法3. 实战讲解 前言 原理&#xff1a;命令行解析使用argparse包作用&#xff1a;命令行传参赋值 可用在机器学习深度学习 或者 脚本运行等 了解这个函数需要了解其背后的原理以及具体参数 1. 函数讲解 在深度学习模型框架中几乎都有的模块 浓…

java打印args的内容_解决java main函数中的args数组传值问题

这几天面试中有遇到关于main数组中的args数组传值的问题,一般是从命令提示符中传值,也可以直接在java代码中赋值。 而且这个数组的长度是动态的,根据传值的个数确定数组的长度。 1.从命令提示符中传值 我在桌面新建了一个文本文档重命名为testmain.java,代码如下 public cl…

k8s args和command

首先先看一下busybox.yaml apiVersion: apps/v1 kind: Deployment metadata:name: app spec:replicas: 2template:metadata:labels:name: appspec:containers:- name: appimage: busybox:1.28.4 #内置的linux大多数命令&#xff0c;多用于测试args:- /bin/sh- -c- slee…

java args的用法_Java中args参数数组的用法说明

main方法args参数用于接收用户输入的参数&#xff0c;参数以字符串形式存放在数组中。 这里将传递参数参数的形式分两种&#xff0c;一种是传递普通参数&#xff0c;另一种是传递含有空格的参数。 1、传递普通参数 public class Test { public static void main(String[] args)…

java args什么意思_java中args是什么意思?

在java中&#xff0c;args是arguments的缩写&#xff0c;是指字符串变量名&#xff0c;属于引用变量&#xff0c;名字代号而已&#xff0c;只是一个默认名&#xff0c;可以自己取的&#xff0c;一般都习惯性照写。String[] args是main函数的形式参数&#xff0c;可以用来获取命…

python args函数_Python函数参数*args 和**kwargs的用法

args就是所有参数的数组&#xff0c;kwargs就是当你传入keyvalue是存储的字典&#xff0c;当函数的参数不确定时&#xff0c;可以使用*args 和kwargs&#xff0c;*args 没有key值&#xff0c;kwargs有key值 def fun_var_args(farg, *args): print "arg:", farg for v…

java args用法_Java中args参数数组的用法说明代码

本篇文章小编给大家分享一下Java中args参数数组的用法说明代码&#xff0c;文章代码介绍的很详细&#xff0c;小编觉得挺不错的&#xff0c;现在分享给大家供大家参考&#xff0c;有需要的小伙伴们可以来看看。 main方法args参数用于接收用户输入的参数&#xff0c;参数以字符串…

C语言关键字浅析-return

### C语言关键字浅析系列 ### ### ISO/ANSI C 关键字 ### return关键字是C程序中最常见的关键字之一 对于一个最简单的demo程序&#xff0c;或者说你最早接触的HELLO WORLD程序&#xff0c;里面至少有两个你最早见到的关键字 int和return&#xff08;注意&#xff0c;inclu…

C语言关键字之inline

简介 inline放在函数返回类型前修饰函数&#xff0c;被修饰的函数就叫做内联函数。 static inline void function&#xff08;void&#xff09;在C语言中&#xff0c;函数调用时保存现场&#xff0c;函数中变量的使用等都会占用栈空间。而且进入函数前的保存现场&#xff0c;…

C语言关键字详解(五)带你全面了解 volatile 关键字

目录 一、前言二、最易变的关键字—volatile1、volatile 总体阐述2、CPU运算与内存覆盖3、线程与执行流4、volatile修饰变量 三、总结 一、前言 大家好&#xff0c;欢迎来到C语言深度解析专栏—C语言关键字详解第五篇&#xff0c;在本篇中我们将会介绍C语言当中的另外一个重要的…

c语言关键字之auto

文章目录 1.c语言中&#xff0c;关键字auto用于声明一个变量为自动变量2.c语言中&#xff0c;只使用auto修饰变量&#xff0c;变量的类型默认为整型3.c中&#xff0c;关键字auto是一个类型说明符题目&#xff1a;编写一段程序&#xff0c;读入一段包含标点符号和空格的字符串&a…

C语言深度解剖——C语言关键字

每天进步一点点&#xff0c;坚持带来大改变&#xff01;&#xff01;&#xff01; 前言&#xff1a; 在C语言的学习过程中会遇到许多的关键字&#xff0c;我们是否真的详细了解这些关键字的使用方法和使用场景&#xff0c;下面我们来详解C语言中的32个关键字 1.C语言关键字概览…

c语言标识符与关键字的关系,C语言关键字与标识符

没有人有资格干涉你的梦想&#xff0c;同样的&#xff0c;也没有人有义务支持你的梦想。能让你坚持或放弃的&#xff0c;终究只有你自己。 标识符 只能以数字&#xff0c;字母和下划线组成&#xff0c;但第一个不能以数字开头。用户自己使用一般第一个也不用下划线(当然也不会出…

c语言什么是关键字,c语言关键字是什么

c语言关键字是什么&#xff1f; c语言关键字又称为保留字,就是已被C语言本身使用,不能作其它用途使用的字。 C语言简洁、紧凑&#xff0c;使用方便、灵活。ANSI C标准C语言共有32个关键字&#xff0c;9种控制语句&#xff0c;程序书写形式自由&#xff0c;区分大小写。把高级语…

C语言的32个基本关键字

1、数据类型关键字&#xff08;12个&#xff09; (1) char &#xff1a;声明字符型变量或函数 注&#xff1a;char 占一个字节&#xff0c;也就是 8 个二进制位&#xff0c;但它表示的是有符号的类型&#xff0c;所以表示的范围是 -128~127 &#xff1b;uchar 表示无符号的类型…

C语言的32个常用关键字

目录 前言 一、关键字是什么&#xff1f; 二、关键字使用方法 1.关键字分类 2.使用方法&#xff08;详解&#xff09; 1.数据类型关键字 int&#xff0c;float&#xff0c;double&#xff0c;charshort&#xff0c;long&#xff0c;signed&#xff0c;unsignedunion&#x…

C语言32个关键字详解

以下内容建议大家收藏&#xff0c;全是干货&#xff0c;建议反复观看&#xff01;&#xff01;&#xff01; Lets Go ! ! ! 首先我们把 C89(C90) 的所有关键字进行一下分类&#xff0c;方便大家理解。 数据类型关键字(12个)&#xff1a; char、short、int、long、signed、unsi…

android将手机能当蓝牙耳机使用吗,一种利用android手机作为蓝牙适配器的蓝牙耳机测试系统及其测试方法与流程...

本发明涉及蓝牙耳机测试的技术领域,特别涉及一种利用android手机作为蓝牙适配器的蓝牙耳机测试系统及其测试方法。 背景技术: 目前蓝牙耳机测试采用如下技术方案: 1、开发蓝牙适配器: 从耳机厂商处获取配置信息,根据配置信息开发蓝牙dongle(蓝牙适配器); 2.测试蓝牙耳机:…