前言
每个开源代码的main函数中都有一个命令行参数解析函数,今天特意参考各种博客资料总结一下。
版本迭代
时间 | 版本 | 版本更新 |
---|---|---|
2024.8.26 | V1.0 | 初始版本 |
参考文档
1.https://blog.csdn.net/qq_41816308/article/details/132899633
2.https://blog.csdn.net/Tschome/article/details/129132082
命令行参数
命令行参数可以分为两类,一类是短选项,一类是长选项,短选项在参数前加一杠"-“,长选项在参数前连续加两杠”–"。-a,-A,-b都表示短选项,–all,–almost-all, --author都表示长选项。
getopt()
声明
#include <unistd.h>
int getopt(int argc, char *const argv[], const char *optstring);
描述
用于解析命令行选项。它通过遍历argv数组中的参数,识别选项字符短选项(例如 -a, -b 等),并根据 optstring指定的选项格式返回结果。每次调用getopt返回一个选项字符,直到没有更多选项。
参数
- argc: 命令行参数的数量。
- argv: 命令行参数数组。
- optstring: 指定合法选项的字符串,选项后面可以跟一个冒号(:)表示该选项需要一个参数。
返回值
- 返回选项字符(例如-a对应a)。
- 如果没有更多选项,返回-1。
- 如果遇到无效选项或缺少参数,返回 ? 或 : 。
实例
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "ab:c")) != -1)
{
switch (opt)
{
case 'a':
printf("Option a\n");
break;
case 'b':
printf("Option b with value %s\n", optarg);
break;
case 'c':
printf("Option c\n");
break;
case '?':
printf("Unknown option\n");
break;
}
}
return 0;
}
结果
假设命令行输入为:
./program -a -b value -c
输出结果将是:
Option a
Option b with value value
Option c
在此示例中,-a 和 -c不需要参数,-b需要一个参数(value),optarg 用于获取 -b 后面的参数值。如果-a或者-c带了参数也不会从optarg中获取到,他会显示NULL。
case 'a':
//printf("Option a\n");
printf("Option a with value %s\n", optarg);
break;
//结果
Option a with value (null)
Option b with value 20
Option c
getopt_long()
声明
#include <getopt.h>
int getopt_long(int argc, char *const argv[], const char *shortopts, const struct option *longopts, int *longindex);
描述
getopt_long() 是一个扩展的getopt()函数,支持长选项(如 --option)以及短选项(如-o)。
参数
- argc: 命令行参数的数量。
- argv: 命令行参数数组。
- shortopts: 一个字符串,定义所有短选项及其参数要求。
- longopts: 一个struct option数组,定义所有长选项及其参数要求。数组最后一个元素必须是全零的结构体。(长选项结构体)
- longindex: 可选参数,用于存储匹配的长选项的索引。如果不需要,可以设置为NULL。
struct option
{
const char *name;
int has_arg;
int *flag;
int val;
};
eg:
static struct option longOpts[] = {
{ "daemon", no_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'd' },
{ "out", required_argument, NULL, 'o' },
{ "log", required_argument, NULL, 'l' },
{ "split", required_argument, NULL, 's' },
{ "http-proxy", required_argument, &lopt, 1 },
{ "http-user", required_argument, &lopt, 2 },
{ "http-passwd", required_argument, &lopt, 3 },
{ "http-proxy-user", required_argument, &lopt, 4 },
{ "http-proxy-passwd", required_argument, &lopt, 5 },
{ "http-auth-scheme", required_argument, &lopt, 6 },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
/*
name:表示选项的名称,比如daemon,dir,out等。
has_arg:表示选项后面是否携带参数。该参数有三个不同值,如下:
no_argument(或者是0)时 ——参数后面不跟参数值,eg: --version,--help
required_argument(或者是1)时 ——参数输入格式为:–参数 值 或者 --参数=值。eg:--dir=home 或者 --dir home
optional_argument(或者是2)时 ——参数输入格式只能为:-–参数=值
flag:空或者非空。
如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。
如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。
val:表示指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值val。
*/
全局变量
-
optarg:表示当前选项对应的参数值。
-
optind:表示的是下一个将被处理到的参数在argv中的下标值。
-
opterr:如果opterr = 0,在getopt、getopt_long、getopt_long_only遇到错误将不会输出错误信息到标准输出流。opterr在非0时,向屏幕输出错误。
-
optopt:表示没有被未标识的选项。
返回值
- 返回选项字符(对于短选项)或longopts中定义的长选项的val字段。
- 如果遇到未知选项或选项格式不正确,则返回?。
- 当所有选项被处理完或达到命令行参数数组的末尾时,返回-1。
实例1
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int main(int argc, char *argv[]) {
int opt;
int option_index = 0;
static struct option long_options[] = {
{"add", no_argument, 0, 'a'},
{"append", no_argument, 0, 'b'},
{"delete", required_argument, 0, 'd'},
{"create", required_argument, 0, 'c'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{0, 0, 0, 0}
};
while ((opt = getopt_long(argc, argv, "ab:d:c:uvV", long_options, &option_index)) != -1) {
switch (opt) {
case 'a':
printf("Option a\n");
break;
case 'b':
printf("Option b\n");
break;
case 'c':
printf("Option c with argument '%s'\n", optarg);
break;
case 'd':
printf("Option d with argument '%s'\n", optarg);
break;
case 'v':
printf("Option v\n");
break;
case 'V':
printf("Option V\n");
break;
case '?':
break;
default:
abort();
}
}
return 0;
}
结果1
运行上面的代码,例如:
./test --add --create file.txt -d 123 --delete 567
会输出:
Option a
Option c with argument 'file.txt'
Option d with argument '123'
Option d with argument '567'
在实例中,–delete和-d是等价的。遇到短选项他会直接到switch中找相应的case,如果是长选项他会先去long_options结构体数组中找对应的第四个参数,如果在去switch中找相应的case。
实例2
本案例主要是讲解longOpts中第三个参数lopt这个参数的作用和option_index的用法。
longOpts中的第三个参数如果是NULL,则第四个参数要使用单个字符;如果给了一个int型的地址,第四个参数要用数字。
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int lopt; // 用于接收选项标志的变量
int main(int argc, char *argv[]) {
int option_index = 0;
int c;
// 定义长选项
static struct option longOpts[] = {
{ "daemon", no_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'd' },
{ "out", required_argument, NULL, 'o' },
{ "log", required_argument, NULL, 'l' },
{ "split", required_argument, NULL, 's' },
{ "http-proxy", required_argument, &lopt, 1 },
{ "http-user", required_argument, &lopt, 2 },
{ "http-passwd", required_argument, &lopt, 3 },
{ "http-proxy-user", required_argument, &lopt, 4 },
{ "http-proxy-passwd", required_argument, &lopt, 5 },
{ "http-auth-scheme", required_argument, &lopt, 6 },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
// 解析命令行选项
while ((c = getopt_long(argc, argv, "D:d:o:l:s:vh", longOpts, &option_index)) != -1) {
printf("Option Index: %d\n", option_index);
switch (c) {
case 'D':
printf("Daemon mode enabled\n");
break;
case 'd':
printf("Directory: %s\n", optarg);
break;
case 'o':
printf("Output file: %s\n", optarg);
break;
case 'l':
printf("Log file: %s\n", optarg);
break;
case 's':
printf("Split size: %s\n", optarg);
break;
case 'v':
printf("Version 1.0\n");
break;
case 'h':
printf("Help: Usage: [options]\n");
break;
case 1: // http-proxy
printf("HTTP Proxy: %s\n", optarg);
break;
case 2: // http-user
printf("HTTP User: %s\n", optarg);
break;
case 3: // http-passwd
printf("HTTP Password: %s\n", optarg);
break;
case 4: // http-proxy-user
printf("HTTP Proxy User: %s\n", optarg);
break;
case 5: // http-proxy-passwd
printf("HTTP Proxy Password: %s\n", optarg);
break;
case 6: // http-auth-scheme
printf("HTTP Auth Scheme: %s\n", optarg);
break;
case '?':
// 错误处理,未知选项
fprintf(stderr, "Unknown option or missing argument\n");
break;
default:
fprintf(stderr, "Unexpected option\n");
break;
}
}
return 0;
}
结果2
./myprogram --daemon --dir /tmp --out output.txt --log error.log --http-proxy http://proxy.example.com --http-user user --http-passwd passwd --version
Option Index: 0
Daemon mode enabled
Option Index: 1
Directory: /tmp
Option Index: 2
Output file: output.txt
Option Index: 3
Log file: error.log
Option Index: 5
Unexpected option
Option Index: 6
Unexpected option
Option Index: 7
Unexpected option
Option Index: 11
Version 1.0
getopt_long_only()
声明
#include <getopt.h>
int getopt_long_only(int argc, char *const argv[], const char *shortopts,
const struct option *longopts, int *longindex);
描述
getopt_long_only()函数用于解析命令行选项,支持长选项的解析,并且不处理短选项。
参数
- argc: 命令行参数的个数,即传递给main函数的argc。
- argv: 命令行参数数组,即传递给main函数的argv。
- shortopts: 一个字符串,定义了短选项。如果不处理短选项,此参数可以是NULL。
- longopts: 一个struct option类型的数组,用于定义长选项。数组的最后一个元素必须是{0, 0, 0, 0}。
- longindex: 指向整数的指针,用于存储长选项的索引。如果不需要,可以将其设置为NULL。
返回值
?
: 遇到未知的选项。:
: 短选项缺少必要的参数。0
: 成功解析了一个长选项,并返回与该长选项对应的字符值。-1
: 解析完成或出错。
实例
#include <getopt.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int opt;
int option_index = 0;
static struct option long_options[] = {
{"add", no_argument, 0, 0},
{"create", required_argument, 0, 0},
{"verbose", no_argument, 0, 0},
{"version", no_argument, 0, 0},
{0, 0, 0, 0}
};
while ((opt = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{
switch (opt)
{
case 0:
printf("Long option %s\n", long_options[option_index].name);
if (long_options[option_index].has_arg == required_argument)
{
printf("With argument: %s\n", optarg);
}
break;
default:
fprintf(stderr, "Usage: %s [--add] [--create arg] [--verbose] [--version]\n", argv[0]);
return 1;
}
}
return 0;
}
结果
运行上述程序时,如果传递以下命令行参数:
./program --add --create example --verbose --version
输出将是:
Long option add
Long option create
With argument: example
Long option verbose
Long option version
总结
getopt():只支持短选项。
getopt_long():支持短选项和长选项。
getopt_long_only():只支持长选项。
如果有错误请帮忙指出,谢谢!