Linux 命令行参数处理函数——getopt

时间:2021-02-09 04:35:42

1 函数原型

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

2 函数描述

2.1 getopt

  功能:getopt()函数解析命令行参数。
  参数argc和argv是程序调用时传递给main()函数的参数参数。其中argc为传入程序参数的个数,默认为1,代表程序自身,argv为指针数组,存放命令行参数,传入的命令行参数以空白符分界,每个元素存放一个字符串,代表一个参数,argv[0]表示程序自身名字*。
  每个argv数组的元素就是一个命令行参数,以 ‘-’(而不是“ - ”或“ - -”)开头的argv元素就是一个选项。该元素(除了初始’ - ‘之外)是选项字符。如果重复调用了getopt(),它会从每个元素中连续返回每个选项字符。如:argv[1] = “-aabc”或 argv[1] =”-a”,那么此时的选项字符都是a。

  参数optstring是选项字符串,比如:”a:b:cd::e”,这就是一个选项字符串。对应到命令行就是-a ,-b ,-c ,-d, -e 。一个冒号就表示这个选项后面必须带有参数(没有带参数会报错哦),但是这个参数可以和选项连在一起写,也可以用空格隔开,比如-a123 和-a 123(中间有空格) 都表示123是-a的参数;两个冒号的就表示这个选项可以有参数,也可以没有参数,但要注意有参数时,参数与选项之间不能有空格(有空格会报错的哦),这一点和一个冒号时是有区别的。

  此外 GNU有额外的扩展。如果optstring包含W后跟分号,则-W foo被视为长选项–foo。 (-W选项由POSIX.2保留,用于实现扩展。)此行为是GNU扩展,在glibc 2之前不可用。

  全局变量optind是要在argv数组中处理的下一个元素的下标(也叫索引)系统将该值初始化为1.调用者可以将其重置为1,以重新扫描相同的argv,或扫描新的参数向量。

  全局变量optarg是用来保存选项的参数的;如果选项无参数则置为NULL。

  全局变量oprerr表示是否将错误信息输出到stderr,为0时表示不输出.

  全局变量optopt表示不在选项字符串optstring中的选项.

  如果getopt()找到另一个选项字符,则返回该字符,更新外部变量optind和一个静态变量nextchar,以便下次调用getopt()可以使用选项字符或argv元素恢复扫描。

  如果没有更多选项字符,getopt()返回-1。那么optind是第一个argv元素的索引,它不是一个选项。

  默认情况下,getopt()在扫描时会排列argv的内容,最终所有既不是选项也不是选项参数的元素都会排到数组末尾。
   还实现了另外两种模式。如果optstring的第一个字符为“+”或设置了环境变量POSIXLY_CORRECT,则一旦遇到非选择参数,选项处理就会停止。如果optstring的第一个字符为’ - ‘,那么每个非选择argv元素都将被处理,就像它是一个带有字符代码1的选项的参数一样。(这被编写用于期望选项和其他argv元素以任何顺序使用的程序,并且关心两者的顺序。)。特殊参数“ - -”强制选择扫描的结束,无论扫描模式如何。

  如果getopt()不识别选项字符,则会向stderr打印一条错误消息,将该字符存储在optopt中,并返回’?’。调用程序可以通过将opterr设置为0来阻止错误消息。

  如果getopt()在argv中找到一个未包含在optstring中的选项字符,或者如果检测到错误的选项参数,则返回’?’并将外部变量optopt设置为实际选项字符。如果optstring的第一个字符(上述可选的’+’或’ - ‘)是冒号(’:’),那么getopt()返回’:’而不是’?’以表示缺少选项参数。如果检测到缺少参数,并且optstring的第一个字符不是冒号,并且外部变量opterr是非零(这是默认值),则getopt()将输出错误消息。

2.2 getopt_long和getopt_long_only

  getopt_long()函数的作用类似于getopt(),但它可以接收接受长选项,以‘–’开头。 (如果程序仅接受长选项,那么optstring应该被指定为一个空字符串(“”),而不是NULL)。如果缩写是唯一的或者可以精确的匹配一些定义的选项,则可以缩写长选项名称。长选项可能会采用–arg = param或–arg param形式的参数。

  参数longopts是指向getopt.h中声明的struct选项数组的第一个元素的指针,通常情况下是一个数组。

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为NULL,那么getopt_long()返回成员val。 (例如,调用程序可以将val设置为等效的短选项字符),否则,getopt_long()返回0,并flag指向一个变量,如果找到该选项,则将该选项设置为val,但如果该选项为未找到则不做改变。

3 返回值

  如果成功找到一个选项,那么getopt()返回选项字符。
  如果所有命令行选项都已被解析,那么getopt()返回-1。
  如果getopt()遇到没有在optstring中的选项字符,那么’?’ 被返回。
   如果getopt()遇到缺少参数的选项,则返回值取决于optstring中的第一个字符:如果为“:”,则返回“:”; 除此以外 ‘?’ 被返回。
   当识别短选项时,getopt_long()和getopt_long_only()也返回选项字符。 对于长选项,如果flag为NULL,则返回val,否则返回0。 错误和-1返回与getopt()相同,加上’?’ 用于模糊匹配或无关的参数。

4 示例

#define _GNU_SOURCE
#include <getopt.h>

void ShowHelpInfo()
{
printf("Usage: BuildCRLCache [option]...\n\n");
printf(" -h, --help display this help\n");
printf(" -v/V, --Version show version\n");
printf(" -d, --crldir directory of crl files\n");
printf(" -c, --cachefile cache filename\n");
printf(" -s, --strictcompare compare crl file by content\n");
printf("\n");
}

int main(int argc , char * argv[])
{
char szCRLDir[256] = "../crl";
char szCacheFile[256] = "./crl.cache";

int ret = 0;
int c = 0;
int option_index = 0;

/**
* 定义命令行参数列表,option结构的含义如下(详见 man 3 getopt):
* struct option {
* const char *name; //参数的完整名称,对应命令中的 --xxx
* int has_arg; //该参数是否带有一个值,如 –config xxx.conf
* int *flag; //一般设置为NULL
* int val; //解析到该参数后getopt_long函数的返回值,为了方便维护,一般对应getopt_long调用时第三个参数
* };
*/


static struct option arg_options[] =
{
{"help", 0, 0, 'h'},
{"version", 0, 0, 'v'},
{"cachefile", 1, 0, 'c'},
{"crldir", 1, 0, 'd'},
{"strictcompare", 1, 0, 's'},
{0, 0, 0, 0}
};

/**
* 注意:传递给getopt_long的第三个参数对应了命令行参数的缩写形式,如-h, -v, -c等,
* 如果字符后面带有冒号,则说明该参数后跟一个值,如-c xxxxxx
*/

while ((c = getopt_long(argc, argv, "hvVc:d:s", arg_options, &option_index)) != -1) {
switch (c) {
case 'h':
ShowHelpInfo();
return 0;
case 'v':
case 'V':
ShowVersionInfo();
return 0;
case 'c':
/* optarg是getopt实现中的一个全局变量,对应当前参数后面跟的值,如-c xxxx中的xxxx */
strncpy( szCacheFile, optarg, sizeof(szCacheFile) );
break;
case 'd':
strncpy( szCRLDir, optarg, sizeof(szCRLDir) );
break;
case 's':
fCompare = CRLFile_Compare;
break;
default:
fprintf( stderr, "Unknown option: %c\n", c);
ShowHelpInfo();
return -1;
}
}