解析命令行参数

  1. 1. man手册
  2. 2. getopt(3)
  3. 3. getopt_long(3)

主要介绍解析命令行参数的两个函数:getopt(),getopt_long()

注:标题中显示的函数数字表示该函数在man手册中所在章节(第2章的是系统调用函数,第3章的是标准函数)

man手册

NAME

getopt, getopt_long - Parse command-line options

SYNOPSIS

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

DESCRIPTION

The getopt() function parses the command-line arguments. Its arguments argc and argv are the argument count and array as passed to the main() function on program invocation. An element of argv that starts with ‘-‘ (and is not exactly “-“ or “–”) is an option element. The characters of this element (aside from the initial ‘-‘) are option characters. If getopt() is called repeatedly, it returns successively each of the option characters from each of the option elements.

The variable optind is the index of the next element to be processed in argv. The system initializes this value to 1. The caller can reset it to 1 to restart scanning of the same argv, or when scanning a new argument vector.

If getopt() finds another option character, it returns that character, updating the external variable optind and a static variable nextchar so that the next call to getopt() can resume the scan with the following option character or argv-element.

If there are no more option characters, getopt() returns -1. Then optind is the index in argv of the first argv-element that is not an option.

optstring is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, so getopt() places a pointer to the following text in the same argv-element, or the text of the following argv-element, in optarg. Two colons mean an option takes an optional arg; if there is text in the current argv-element (i.e., in the same word as the option name itself, for example, “-oarg”), then it is returned in optarg, otherwise optarg is set to zero. This is a GNU extension. If optstring contains W followed by a semicolon, then -W foo is treated as the long option –foo. (The -W option is reserved by POSIX.2 for implementation extensions.) This behavior is a GNU extension, not available with libraries before glibc 2.

By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end. Two other modes are also implemented. If the first character of optstring is ‘+’ or the environment variable POSIXLY_CORRECT is set, then option processing stops as soon as a nonoption argument is encountered. If the first character of optstring is ‘-‘, then each nonoption argv-element is handled as if it were the argument of an option with character code 1. (This is used by programs that were written to expect options and other argv-elements in any order and that care about the ordering of the two.) The special argument “–” forces an end of option-scanning regardless of the scanning mode.

If getopt() does not recognize an option character, it prints an error message to stderr, stores the character in optopt, and returns ‘?’. The calling program may prevent the error message by setting opterr to 0.

If getopt() finds an option character in argv that was not included in optstring, or if it detects a missing option argument, it returns ‘?’ and sets the external variable optopt to the actual option character. If the first character (following any optional ‘+’ or ‘-‘ described above) of optstring is a colon (‘:’), then getopt() returns ‘:’ instead of ‘?’ to indicate a missing option argument. If an error was detected, and the first character of optstring is not a colon, and the external variable opterr is nonzero (which is the default), getopt() prints an error message.

getopt_long() and getopt_long_only()

The getopt_long() function works like getopt() except that it also accepts long options, started with two dashes. (If the program accepts only long options, then optstring should be specified as an empty string (“”), not NULL.) Long option names may be abbreviated if the abbreviation is unique or is an exact match for some defined option. A long option may take a parameter, of the form –arg=param or –arg param.

longopts is a pointer to the first element of an array of struct option declared in <getopt.h> as

struct option {

const char *name;

int has_arg;

int *flag;

int val;

};

The meanings of the different fields are:

name is the name of the long option.

has_arg is: no_argument (or 0) if the option does not take an argument; required_argument (or 1) if the option requires an argument; or optional_argument (or 2) if the option takes an optional argument.

flag specifies how results are returned for a long option. If flag is NULL, then getopt_long() returns val. (For example, the calling program may set val to the equivalent short option character.) Otherwise, getopt_long() returns 0, and flag points to a variable which is set to val if the option is found, but left unchanged if the option is not found.

val is the value to return, or to load into the variable pointed to by flag.

The last element of the array has to be filled with zeros.

If longindex is not NULL, it points to a variable which is set to the index of the long option relative to longopts.

getopt_long_only() is like getopt_long(), but ‘-‘ as well as “–” can indicate a long option. If an option that starts with ‘-‘ (not “–”) doesn’t match a long option, but does match a short option, it is parsed as a short option instead.

RETURN VALUE

If an option was successfully found, then getopt() returns the option character. If all command-line options have been parsed, then getopt() returns -1. If getopt() encounters an option character that was not in optstring, then ‘?’ is returned. If getopt() encounters an option with a missing argument, then the return value depends on the first character in optstring: if it is ‘:’, then ‘:’ is returned; otherwise ‘?’ is returned.

getopt_long() and getopt_long_only() also return the option character when a short option is recognized. For a long option, they return val if flag is NULL, and 0 otherwise. Error and -1 returns are the same as for getopt(), plus ‘?’ for an ambiguous match or an extraneous parameter.

getopt(3)

getopt() 函数用于解析命令行参数并返回对应的选项和参数。函数原型如下:

1
2
3
4
5
#include <unistd.h>

int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;

参数说明:

  • argc:命令行参数个数,包括程序名本身。

  • argv:指向命令行参数字符串数组的指针,其中包括程序名和各个参数。

  • optstring:包含所有有效选项的字符串,表示程序所支持的命令行选项。optstring中的每个字符表示一个选项:

    • 大写字母表示可以带参数的选项;
    • 小写字母表示不带参数的选项;
    • 冒号(:)表示该选项必须带一个参数;
  • optarg:指向当前选项参数的指针。当 getopt() 解析到带有参数的选项时,可以通过访问 optarg 来获取该参数的值。

  • optind:表示下一个要处理的参数索引。初始值为 1,每次调用 getopt() 后会自动更新,程序名、选项及其参数占据前几个位置,之后才是剩余参数。

  • opterr:控制是否显示错误信息。如果设置为 0,getopt() 函数将不会打印错误信息到标准错误流(stderr);如果设置为非零值,getopt() 函数将会打印错误信息到 stderr。

  • optopt:用于保存无效选项字符(即不在 optstring 中的字符),以便在需要时进行处理。

函数返回值:

  • 如果找到合法选项,则返回选项的ASCII码。
  • 如果所有的命令行选项都解析完毕,则返回-1。
  • 如果遇到非法选项字符,则返回?,并将 optopt 变量设为非法选项字符的ASCII码。

注意事项:

  1. 当 getopt() 函数返回一个选项代码时,全局变量 optarg 将指向选项的参数,全局变量 optind 将指向下一个待处理的命令行参数的位置。
  2. 注意区分以下概念:选项、参数、选项参数、非选项参数。

举个栗子:

task:以指定格式显示当前系统时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// mydate.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

/*
* -y: year
* -m: month
* -d: day
* -H: hour
* -M: minute
* -S: second
* */

#define TIMESTRSIZE 1024
#define FMTSTRSIZE 1024

int main(int argc,char **argv)
{
time_t stamp;
struct tm *tm;
char timestr[TIMESTRSIZE];
int c;
char fmtstr[FMTSTRSIZE];
FILE *fp = stdout;

fmtstr[0] = '\0';

time(&stamp);
tm = localtime(&stamp);

while(1)
{
c = getopt(argc,argv,"-H:MSy:md");
if(c < 0)
break;

switch (c)
{
case 1:
/*
* choose the first file:
* eg: ./mydate -y 4 /tmp/out -m /tmp/out2 -d /tmp/out3
*/
if(fp == stdout)
{
fp = fopen(argv[optind-1],"w");
if(fp == NULL)
{
perror("fopen()");
fp = stdout;
}
}
break;
case 'H':
// strncat(fmtstr,"%H ",FMTSTRSIZE);
if(strcmp(optarg,"12") == 0)
strncat(fmtstr,"%I(%P) ",FMTSTRSIZE);
else if(strcmp(optarg,"24") == 0)
strncat(fmtstr,"%H ",FMTSTRSIZE);
else
fprintf(stderr,"Invalid argument of '-H'\n");
break;
case 'M':
strncat(fmtstr,"%M ",FMTSTRSIZE);
break;
case 'S':
strncat(fmtstr,"%S ",FMTSTRSIZE);
break;
case 'y':
// strncat(fmtstr,"%y ",FMTSTRSIZE);
if(strcmp(optarg,"2") == 0)
strncat(fmtstr,"%y ",FMTSTRSIZE);
else if(strcmp(optarg,"4") == 0)
strncat(fmtstr,"%Y ",FMTSTRSIZE);
else
fprintf(stderr,"Invalid argument of '-y'\n");
break;
case 'm':
strncat(fmtstr,"%m ",FMTSTRSIZE);
break;
case 'd':
strncat(fmtstr,"%d ",FMTSTRSIZE);
break;
default:
break;
}
}

strftime(timestr,TIMESTRSIZE,fmtstr,tm);
fprintf(fp,"%s\n",timestr);

if(fp != stdout)
{
fclose(fp);
}

exit(0);
}

注:实现mydate.c程序时,可以按照如下顺序:mdMS,Hy,非选项的传参,文件的操作。

getopt_long(3)

getopt_long() 函数与getopt() 函数类似,也是用于解析命令行参数的函数。但相较于getopt(),它支持更复杂的选项处理,包括长选项(长格式的命令行选项,例如 --help)以及更多的自定义配置。函数原型如下:

1
2
3
4
5
#include <getopt.h>

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

参数说明:

  • argc:命令行参数个数,包括程序名本身。
  • argv:指向命令行参数字符串数组的指针,其中包括程序名和各个参数。
  • optstring:类似于getopt() 的选项字符串,表示程序所支持的短选项。
  • longopts:一个指向struct option类型的数组,表示程序所支持的长选项。数组中的每个元素都是一个 option 结构体,其定义如下:
1
2
3
4
5
6
struct option {
const char *name; // 长选项的名称
int has_arg; // 指定是否需要参数,可以是 no_argument (0),required_argument (1),或 optional_argument (2)
int *flag; // 用于决定如何返回结果,如果 flag 是 NULL,getopt_long() 返回的是 val 的值,否则返回 0,并将 flag 指向的变量设置为 val
int val; // 如果选项被找到,val 是返回的值,或者加载到 flag 指向的变量中
};
  • longindex:用于返回当前长选项在longopts数组中的索引,通常可设置为 NULL。

函数返回值:

  • 如果找到合法选项,返回选项的短选项字符或者长选项的val字段。
  • 如果所有命令行选项都解析完毕,则返回-1。
  • 如果遇到非法选项字符或者无法匹配的长选项,则返回?

注意事项:

  1. 在选项数组(option array)中,最后一个元素必须全部填充为零,表示数组的结束。