简介
getopt函数是命令行参数解析函数,在平时阅读源码的时候经常遇到,很有必要对其总结一下,做个记录!


命令行参数各组成部分的名称
先来了解下命令行参数各组成部分的名称。直接上图:

非常清楚,命令行参数由Command name,Option,Option argument 以及Operands组成。
Command name不用多说,就是程序的名称。
操作对象Operands又称nonoption argument。
重点就是这里的选项Option了,它是用来用来决定程序的行为,而选项参数Option argument是选项Option所需要的信息。


getopt()函数

#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);  

getopt()函数将传递给mian()函数的argc,argv作为参数,同时接受字符串参数optstring -- optstring是由选项Option字母组成的字符串。关于optstring的格式规范简单总结如下:
(1) 单个字符,表示该选项Option不需要参数。
(2) 单个字符后接一个冒号":",表示该选项Option需要一个选项参数Option argument。选项参数Option argument可以紧跟在选项Option之后,或者以空格隔开。选项参数Option argument的首地址赋给optarg。
(3) 单个字符后接两个冒号"::",表示该选项Option的选项参数Option argument是可选的。当提供了Option argument时,必须紧跟Option之后,不能以空格隔开,否则getopt()会认为该选项Option没有选项参数Option argument,optarg赋值为NULL。相反,提供了选项参数Option argument,则optarg指向Option argument。

为了使用getopt(),我们需要在while循环中不断地调用直到其返回-1为止。每一次调用,当getopt()找到一个有效的Option的时候就会返回这个Option字符,并设置几个全局变量。
getopt()设置的全局变量包括:
char *optarg  -- 当匹配一个选项后,如果该选项带选项参数,则optarg指向选项参数字符串;若该选项不带选项参数,则optarg为NULL;若该选项的选项参数为可选时,optarg为NULL表明无选项参数,optarg不为NULL时则指向选项参数字符串。

int optind  -- 下一个待处理元素在argv中的索引值。即下一次调用getopt的时候,从optind存储的位置处开始扫描选项。当getopt()返回-1后,optind是argv中第一个Operands的索引值。optind的初始值为1。
int opterr  -- opterr的值非0时,在getopt()遇到无法识别的选项,或者某个选项丢失选项参数的时候,getopt()会打印错误信息到标准错误输出。opterr值为0时,则不打印错误信息。
int optopt  -- 在上述两种错误之一发生时,一般情况下getopt()会返回'?',并且将optopt赋值为发生错误的选项。

使用getopt()时,会犯的错误无外乎有两个:无法识别的选项(Invalid option) 和丢失选项参数(Missing option argument)
通常情况下,getopt()在发现这两个错误时,会打印相应的错误信息,并且返回字符"?" 。例如,遇见无法识别的选项时会打印"invalid option",发现丢失参数时打印"option requires an argument"。但是当设置opterr为0时,则不会打印这些信息,因此为了便于发现错误,默认情况下,opterr都是非零值。

如果你想亲自处理这两种错误的话,应该怎么做呢? 首先你要知道什么时候发生的错误是无法识别的选项,什么时候发生的错误是丢失选项参数。如果像上面描述的那样,都是返回字符"?"的话,肯定是无法分辨出的。有什么办法吗? 有! getopt()允许我们设置optstring的首字符为冒号":",在这种情况下,当发生无法识别的选项错误时getopt()返回字符"?",当发生丢失选项参数错误时返回字符":"。这样我们就可以很轻松地分辨出错误类型了,不过代价是getopt()不会再打印错误信息了,一切事物都由我们自己来处理了。


getopt()扫描模式
关于getopt()的扫描模式,man文档说的不是很清楚,这里通过实例来阐释,尽量做到简单明了,一看即懂。
getopt()的默认模式扫描模式是这样的:getopt()从左到右按顺序扫描argv[1]到argv[argc-1],并将选项Option和选项参数Option argument按它们在命令行上出现的次序放到argv数组的左边,而那些Operands则按它们出现的次序放在argv的后边。也就是说,getopt()在默认扫描模式下,会重新排序argv数组。
来看个实例,假设我们调用getopt(argc, argv, "ab:c:de::");
从前面的知识点,我们很容易得出结论:选项a,d是不需要选项参数的,选项b,c需要选项参数,而选项e的选项参数是可选的,即如果提供选项e的选项参数的话,那么选项参数必须紧跟选项e之后,不能以空格隔开。

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>  static int cnt = 1;  static void print(int optc, int argc, char *argv[], int optind)
{  int i;  printf("%02d: optc - '%c', argv: ", cnt++, optc);  for (i = 0; i < argc; i++) {  printf("%s ", argv[i]);  }  printf("---- optind = %d\n", optind);
}  int main(int argc, char *argv[])
{  int optc;  print('0', argc, argv, optind);  while ((optc = getopt(argc, argv, ":ab:c:de::")) != -1) {  print(optc, argc, argv, optind);  switch (optc) {  default:  break;  }  }  print('0', argc, argv, optind);  exit(EXIT_SUCCESS);
}  

以下是实际的运行情况:

当然在真实情况下,一个程序很少需要这么多的Operands,这里只是为了更清楚地演示getopt()是如何扫描命令行参数的。
扫描过程中,要时刻铭记optind是下一个待处理元素在argv中的索引,当遇到Operands的时候则跳过,optind数值增加跳过的Operands个数。好,现在我们根据这些规则,详细分析下刚刚程序的扫描过程:
第一行:即getopt()扫描重排序之前,可以看到optind的值默认被初始化为1。
第二行:getopt()首先从operand1开始扫描,发现operand1是Operands,则跳过,optind增加1等于2指向-a,继续扫描。扫描到-a时发现是有效选项,则optind增加1等于3指向operand2,然后返回选项a。
第三行:在继续扫描前,getopt()重新排序argv数组,将“-a”和“operand1”的位置互换。继续扫描,发现operand2是Operands,跳过,optind增加1等于4指向-b,继续扫描。发现-b是有效选项,因为选项b需要参数,因此把barg的首地址赋给optarg,optind增加2等于6指向operand3,返回选项b。
第四行:在继续扫描前,getopt()重新排序argv数组,将“-b barg”和“operand1 operand2”的位置互换。继续扫描,发现operand3是Operands,跳过,optind增加1等于7指向-c,继续扫描。扫描到-c是发现是有效的选项,因为选项c跟选项b一样,都需要参数,因此处理过程是一样的,把carg的首地址赋给optarg,optind增加2等于9指向operand4,返回选项c。
第五行:在继续扫描前,getopt()重新排序argv数组,将“-c carg”和“operand1 operand2 operand3”的位置互换。继续扫描,发现operand4是Operands,跳过,optind增加1等于10指向-d,继续扫描。扫描到-d时发现是有效选项,因为选项d不需要参数,因此直接optind增加1等于11指向operand5,返回选项d。
第六行:在继续扫描前,getopt()重新排序argv数组,将“-d”和“operand1 operand2 operand3 operand4”的位置互换。继续扫描,发现operand5是Operands,跳过,optind增加1等于12指向operand6,继续扫描。扫描到operand6时发现依然是Operands,跳过,optind增加1等于13指向-e,继续扫描。扫描到-e时发现是有效选项,因为后面的operand7与-e之间有间隔,因此这里选项e没有参数。optind增加1等于14指向operand7,返回选项e。
第七行:在继续扫描前,getopt()重新排序argv数组,将“-e”和“operand1 operand2 operand3 operand4 operand5 operand6”的位置互换。继续扫描,发现operand7是Operands,跳过,optind增加1等于15指向argv[argc],即NULL。至此扫描完毕,getopt()重新设置optind为8,是其指向第一个Operands,即operand1,最后返回-1停止扫描。

如果想要查看更多详细信息的话可以man一下,上面有一个小的例子提供参考

getopt()函数详解相关推荐

  1. linux系统getopt函数详解

    getopt()函数就是用来解析命令行参数 调用形式一般如下: while((c = getopt(argc, argv, "xy:z::")) != -1){ switch(c) ...

  2. python中getopt函数详解

    在运行程序时,可能需要根据不同的条件,输入不同的命令行选项来实现不同的功能.目前有短选项和长选项两种格式.短选项格式为"-"加上单个字母选项:长选项为"--"加 ...

  3. python中getopt函数_python getopt函数详解

    getopt模块可以帮助脚本解析sys.argv的命令行参数,它遵守和Unix getopt()函数相同的约定,该模块提供两个函数和一个异常. 1. getopt.getopt(args, optio ...

  4. getopt函数详解

    getopt函数 1.定义: int getopt(int argc, char * const argv[], const char *optstring); 注意!!!! 使用之后,会对参数的顺序 ...

  5. linux下wait函数,Linux wait函数详解

    wait和waitpid出现的原因 SIGCHLD --当子进程退出的时候,内核会向父进程SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) --子进程退出时,内核将 ...

  6. C语言网络编程:accept函数详解

    文章目录 前言 函数描述 代码实例 如何得到客户端的IP 和 端口号 前言 当使用tcp服务器使用socket创建通信文件描述符,bind绑定了文件描述符,服务器ip和端口号,listen将服务器端的 ...

  7. 【FFmpeg】函数详解(三)

    FFmpeg函数详解 14.av_write_frame 15.av_interleaved_write_frame 16.av_write_trailer 17.avio_close 18.av_i ...

  8. 【FFmpeg】函数详解(二)

    FFmpeg函数详解 9.av_dump_format 10.avio_open 11.avformat_write_header 12.avcodec_send_frame 13.avcodec_r ...

  9. 【FFmpeg】函数详解(一)

    FFmpeg函数详解 一.错误码相关 1.AVERROR 2.av_strerror 3.其他错误码解释 二.编解码 1.获取编解码器 2.申请.释放上下文环境 3.打开编码器avcodec_open ...

最新文章

  1. 计算机组成原理——知识结构体系
  2. vue main.js 引入 全局 js 统一导入 js
  3. Embedding Lua, in Scala, using Java(转)
  4. Linux下rz,sz
  5. 2.3 快速搭建你的第一个系统,并进行迭代-深度学习第三课《结构化机器学习项目》-Stanford吴恩达教授
  6. Go语言的多态(Polymorphism)
  7. python自动炒股软件下载_python自动股票交易软件
  8. 怎么挪动_2020蚕茧多少钱一斤,蚕茧怎么做成蚕丝被
  9. 【机器学习】机器学习从零到掌握之九 -- 教你使用K近邻算法形成完整系统
  10. 在 VMware ESXi 5.5 和 6.0.x 中支持大于 2 TB 的虚拟机磁盘 (2058287)
  11. android中FileObserver的运用
  12. [HihoCoder1369]网络流一·Ford-Fulkerson算法
  13. 04-jQuery的属性操作
  14. c语言编写记账程序,C语言会计记账管理系统
  15. 飞鸽传书软件局域网传输文件
  16. 什么是网站服务器 域名 备案号,什么是网站服务器 域名 备案
  17. 已解决(Python运行报错)SyntaxError: expression cannot contain assignment, perhaps you meant “==“?
  18. 改革人工智能时代的劳动技能教育
  19. 一阶电路实验报告心得_电路实训心得体会
  20. 25. 获取员工其当前的薪水比其manager当前薪水还高的相关信息

热门文章

  1. 记录 PPT免费模板网站
  2. 金仓数据库KingbaseES客户端编程开发框架-Django(3. 使用说明)
  3. PYTHON-def函数定义和调用
  4. 关联规则算法——Apriori算法
  5. MySQL MyCAT 读写分离实战
  6. ~109美图手机官网移动端
  7. [源码和文档分享]使用TerminateProcess函数实现结束指定进程
  8. C#连接OPC server失败,报错80040154 没有注册类
  9. IDEA创建Meven项目
  10. Unity Sqlite的使用与简单封装