C++函数 - getopt函数分析以及命令行解析

在Linux下运行可执行程序时,一般需要带特定参数以指定运行的方式。通过是采用getopt()函数解析传入的参数内容,其头文件为<unistd.h>。

下面来具体介绍getopt的原型:

int getopt(int argc,char * const argv[ ],const char * optstring);
1

参数argc和argv分别代表参数个数和内容,参数 optstring为选项字符串。

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

  • extern char *optarg;
  • extern int optind, opterr, optopt;
  • optarg——指向当前选项参数(如果有)的指针。
  • optind——再次调用 getopt() 时的下一个 argv 指针的索引。
  • opterr——是否将错误信息输出到stderr,为0时表示不输出。
  • optopt——不在选项字符串optstring中的选项。

选项和参数的概念:

  • 单个字符,表示选项;(例如 g++ -o main main.cpp -std=c++11,其中o就是命令行的选项,而后面的main就是选项所带的参数。)
  • 单个字符后接一个冒号: 表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
  • 单个字符后跟两个冒号,表示该选项后必须跟一个参数。参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。

短参数的定义:

getopt()使用optstring所指的字串作为短参数列表,像"1ac:d::"就是一个短参数列表。短参数的定义是一个'-'后面跟一个字母或数字,例如-a, -b就是一个短参数。每个数字或字母定义一个参数。

其中短参数在getopt定义里分为三种:

1. 不带值的参数,它的定义即是参数本身。  2. 必须带值的参数,它的定义是在参数本身后面再加一个冒号。  3. 可选值的参数,它的定义是在参数本身后面加两个冒号 。

以"1ac:d::"为例,其中的1,a就是不带值的参数,c是必须带值的参数,d是可选值的参数。   在实际调用中,'-1 -a -c cvalue -d', '-1 -a -c cvalue -ddvalue', '-1a -ddvalue -c cvalue'都是合法的。注意事项:

1. 不带值的参数可以连写,像1和a是不带值的参数,它们可以-1 -a分开写,也可以-1a或-a1连写。  2. 参数不分先后顺序,'-1a -c cvalue -ddvalue'和'-d -c cvalue -a1'的解析结果是一样的。  3. 要注意可选值的参数的值与参数之间不能有空格,必须写成-ddvalue这样的格式,如果写成-d dvalue这样的格式就会解析错误。

测试程序1,解析输入的ip,port和msg:

  1. 类的this可以通过对象或者指针来绑定

测试程序1:

DETAILS
#include <iostream>
#include <unistd.h>
#include <string>

using namespace std;

//解析ip, port, msg.
void testFun1(int argc, char *argv[])
{
    std::string ip = "127.0.0.1";
	int port = 8080;
	std::string msg = "Hello World";
	
	int opt;
    const char *str = "i:p:m:";
    while ((opt = getopt(argc, argv, str)) != -1)
    {
        switch (opt)
        {
        case 'i':
        {
            ip = optarg;
            break;
        }
        case 'p':
        {
            port = atoi(optarg);
            break;
        }
        case 'm':
        {
            msg = optarg;
            break;
        }
        default:
            break;
        }
    }
	cout<<"ip: "<<ip<<endl;
	cout<<"port: "<<port<<endl;
	cout<<"msg: "<<msg<<endl;
}

//解析2ab:c:de::
void testFun2(int argc, char *argv[])
{

	int opt;
    const char *str = "2ab:c:de::";
    while ((opt = getopt(argc, argv, str)) != -1)
    {
        switch (opt)
        {
            case '2':
				cout<<"HAVE option: -2"<<endl;
                break;
			case 'a':
				cout<<"HAVE option: -a"<<endl;
                break;
            case 'b':
                cout<<"HAVE option: -b"<<endl;
				cout<<"The value of -b is "<<optarg<<endl;
				break;
			case 'c':
				cout<<"HAVE option: -c"<<endl;
                cout<<"The value of -c is "<<optarg<<endl; 
                break;
            case 'd':
                cout<<"HAVE option: -d"<<endl;
				 break;
			case 'e':
				cout<<"HAVE option: -e"<<endl;
                cout<<"The value of -e is "<<optarg<<endl;
                break;
			default:
				break;
        }
    }
}

int main(int argc, char *argv[])
{
	//testFun1(argc,argv);
	testFun2(argc,argv);
    return 0;
}

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

执行结果: bash

[root@192 main函数命令行解析]# ./main
ip: 127.0.0.1
port: 8080
msg: Hello World
[root@192 main函数命令行解析]# ./main -i 10.43.33.115 -p 8888 -m Test
ip: 10.43.33.115
port: 8888
msg: Test
1
2
3
4
5
6
7
8

测试程序2,解析输入的"abcde":

执行结果:

[root@192 main函数命令行解析]# ./main -a -b 123 -c 456 -d -e 555
HAVE option: -a
HAVE option: -b
The value of -b is 123
HAVE option: -c
The value of -c is 456
HAVE option: -d
HAVE option: -e
The value of -e is [root@192 main函数命令行解析]# ./main -b 123 -c 456 -d -e555 -a2
HAVE option: -b
The value of -b is 123
HAVE option: -c
The value of -c is 456
HAVE option: -d
HAVE option: -e
The value of -e is 555
HAVE option: -a
HAVE option: -2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18