LINUX下getopt函数的简单使用

本文详细解析了getopt()函数的使用方法,包括其参数、返回值及常见错误处理方式。并通过实例展示了如何通过getopt()解析命令行参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

英雄不问出处,getopt()函数的出处就是unistd.h头文件(哈哈),写代码的时候千万不要忘记把他老人家include上。

 

再来看一下这家伙的原型(不是六耳猕猴):

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

前两个参数大家不会陌生,没错,就是老大main函数的两个参数!老大传进来的参数自然要有人接着!

第三个参数是个字符串,看名字,我们可以叫他选项字符串(后面会说明)

返回值为int类型,我们都知道char类型是可以转换成int类型的,每个字符都有他所对应的整型值,其实这个返回值返回的就是一个字符,什么字符呢,叫选项字符(姑且这么叫吧,后面会进一步说明)

简单了解了出身和原型,下面我们看看这家伙到底有什么本事吧!

(⊙o⊙)…在此之前还要介绍他的几个兄弟~~~~呃呃呃

小弟1、extern char* optarg;

小弟2、extern int optind;

小弟3、extern int opterr;

小弟4、extern int optopt;

队形排的不错。小弟1是用来保存选项的参数的(先混个脸熟,后面有例子);小弟2用来记录下一个检索位置;小弟3表示的是是否将错误信息输出到stderr,为0时表示不输出,小弟4表示不在选项字符串optstring中的选项(有点乱哈,后面会有例子)

开始逐渐解释上面遗留的问题。

问题1:选项到底是个什么鬼?

在linux下大家都用过这样一条指令吧:gcc helloworld.c -o helloworld.out; 这条指令中的-o就是命令行的选项,而后面的helloworld.out就是-o选项所携带的参数。当然熟悉shell指令的人都知道(虽然我并不熟悉),有些选项是不用带参数的,而这样不带参数的选项可以写在一起(这一点在后面的例子中会用到,希望理解,比如说有两个选项-c和-d,这两个选项都不带参数(而且明显是好基友),那么他们是可以写在一起,写成-cd的。实际的例子:当我们删除一个文件夹时可以使用指令 rm 目录名 -rf,本来-r表示递归删除,就是删除文件夹中所有的东西,-f表示不提示就立刻删除,他们两个都不带参数,这时他们就可以写在一起。

问题2:选项字符串又是何方神圣?

还是看个例子吧

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

好了,先给个代码,然后再解释吧。

复制代码
#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
    
    int ch;
    printf("\n\n");
    printf("optind:%d,opterr:%d\n",optind,opterr);
    printf("--------------------------\n");
       while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
       {
        printf("optind: %d\n", optind);
           switch (ch) 
        {
               case 'a':
                       printf("HAVE option: -a\n\n");   
                       break;
               case 'b':
                       printf("HAVE option: -b\n"); 
                       printf("The argument of -b is %s\n\n", optarg);
                       break;
               case 'c':
                       printf("HAVE option: -c\n");
                       printf("The argument of -c is %s\n\n", optarg);
                       break;
               case 'd':
                   printf("HAVE option: -d\n");
                     break;
              case 'e':
                    printf("HAVE option: -e\n");
                    printf("The argument of -e is %s\n\n", optarg);
                  break;
              case '?':
                       printf("Unknown option: %c\n",(char)optopt);
                       break;
               }
       }


}
复制代码

 

编译后命令行执行:# ./main -b "qing er"

输出结果为:

optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er

 

我们可以看到:optind和opterr的初始值都为1,前面提到过opterr非零表示产生的错误要输出到stderr上。那么optind的初值为什么是1呢?

这就要涉及到main函数的那两个参数了,argc表示参数的个数,argv[]表示每个参数字符串,对于上面的输出argc就为3,argv[]分别为: ./main 和 -b 和"qing er" ,实际上真正的参数是用第二个-b 开始,也就是argv[1],所以optind的初始值为1;

当执行getopt()函数时,会依次扫描每一个命令行参数(从下标1开始),第一个-b,是一个选项,而且这个选项在选项字符串optstring中有,我们看到b后面有冒号,也就是b后面必须带有参数,而"qing er"就是他的参数。所以这个命令行是符合要求的。至于执行后optind为什么是3,这是因为optind是下一次进行选项搜索的开始索引,也是说下一次getopt()函数要从argv[3]开始搜索。当然,这个例子argv[3]已经没有了,此时getopt()函数就会返回-1。

再看一个输入:

 ./main -b "qing er" -c1234

输出结果为:

optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er

optind: 4
HAVE option: -c
The argument of -c is 1234

 

对于这个过程会调用三次getopt()函数,和第一个输入一样,是找到选项-b和他的参数"qing er",这时optind的值为3,也就意味着,下一次的getopt()要从argv[3]开始搜索,所以第二次调用getopt()函数,找到选项-c和他的参数1234(选项和参数是连在一起的),由于-c1234写在一起,所以他两占一起占用argv[3],所以下次搜索从argv[4]开始,而argv[4]为空,这样第三次调用getopt()函数就会返回-1,循环随之结束。

 

接下来我们看一个错误的命令行输入: ./main -z 123

输出为:

optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 2
Unknown option: z

其中./main: invalid option -- 'z'就是输出到stderr的错误输出。如果把opterr设置为0那么就不会有这条输出。

 

在看一个错误的命令行输入: ./main -zheng

 

optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 1
Unknown option: z
./main: invalid option -- 'h'
optind: 1
Unknown option: h
optind: 2
HAVE option: -e
The argument of -e is ng

前面提到过不带参数的选项可以写在一起,所以当getopt()找到-z的时候,发现在optstring 中没有,这时候他就认为h也是一个选项,也就是-h和-z写在一起了,依次类推,直到找到-e,发现optstring中有。

 

最后要说明一下,getopt()会改变argv[]中参数的顺序。经过多次getopt()后,argv[]中的选项和选项的参数会被放置在数组前面,而optind 会指向第一个非选项和参数的位置。看例子

复制代码
#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
    
    int i;
    printf("--------------------------\n");
    for(i=0;i<argc;i++)
    {
        printf("%s\n",argv[i]);
    }
    printf("--------------------------\n");
       //int aflag=0, bflag=0, cflag=0;
    
       int ch;
    printf("\n\n");
    printf("optind:%d,opterr:%d\n",optind,opterr);
    printf("--------------------------\n");
       while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
       {
        printf("optind: %d\n", optind);
           switch (ch) 
        {
               case 'a':
                       printf("HAVE option: -a\n\n");   
                       break;
               case 'b':
                       printf("HAVE option: -b\n"); 
                       printf("The argument of -b is %s\n\n", optarg);
                       break;
               case 'c':
                       printf("HAVE option: -c\n");
                       printf("The argument of -c is %s\n\n", optarg);
                       break;
               case 'd':
                   printf("HAVE option: -d\n");
                     break;
              case 'e':
                    printf("HAVE option: -e\n");
                    printf("The argument of -e is %s\n\n", optarg);
                  break;
              case '?':
                       printf("Unknown option: %c\n",(char)optopt);
                       break;
               }
       }
    
       printf("----------------------------\n");
      printf("optind=%d,argv[%d]=%s\n",optind,optind,argv[optind]);

    printf("--------------------------\n");
    for(i=0;i<argc;i++)
    {
        printf("%s\n",argv[i]);
    }
    printf("--------------------------\n");
    

}
复制代码

 

 命令行:./main zheng -b "qing er" han -c123 qing

 

输出结果为:

--------------------------
./main
zheng
-b
qing er
han
-c123
qing
--------------------------


optind:1,opterr:1
--------------------------
optind: 4
HAVE option: -b
The argument of -b is qing er

optind: 6
HAVE option: -c
The argument of -c is 123

----------------------------
optind=4,argv[4]=zheng
--------------------------
./main
-b
qing er
-c123
zheng
han
qing
--------------------------

 

可以看到最开始argv[]内容为:

./main
zheng
-b
qing er
han
-c123
qing

 

在执行了多次getopt后变成了

./main
-b
qing er
-c123
zheng
han
qing

我们看到,被getopt挑出的选项和对应的参数都按顺序放在了数组的前面,而那些既不是选项又不是参数的会按顺序放在后面。而此时optind为4,即指向第一个非选项也非选项的参数

转自:https://www.cnblogs.com/qingergege/p/5914218.html



<think>好的,用户想了解Linux C中的getopt函数。我需要先回忆一下这个函数的基本用途和相关知识。getopt是用来解析命令行参数的,这在写命令行工具的时候特别有用。它属于unistd.h头文件,所以需要包含这个头文件。 首先,我应该介绍getopt的基本功能,比如如何处理短选项和参数。比如像-a、-b这样的短选项,以及像-ovalue或者-o value这样的参数。需要说明optstring的格式,比如字母后面跟冒号表示需要参数,两个冒号表示可选参数。 然后,可能需要给出函数原型,说明参数argc、argv和optstring的作用。还要提到全局变量optarg、optind、opterr和optopt,这些变量在解析过程中会被修改,用来存储参数值、索引等。 接下来,可能需要一个示例代码,展示如何使用getopt循环处理选项。例如,一个常见的循环结构,用while和switch来处理每个选项,比如-h显示帮助,-v显示版本,-o带参数等。这样用户能更直观地理解怎么用。 还需要注意一些常见问题和陷阱,比如optstring的正确格式,选项参数的获取方式,以及错误处理。例如,当用户输入未定义的选项时,getopt会返回'?',这时候可能需要提示错误信息。另外,处理完选项后,剩下的非选项参数可以通过argv + optind来访问,这部分也要提醒用户。 另外,可以提到getoptgetopt_long的区别,后者支持长选项,但可能用户暂时只需要了解getopt的基本用法。最后,确保回答结构清晰,分步骤说明,让用户能够逐步理解和应用这个函数。</think>Linux C 中的 `getopt` 函数是用于解析命令行参数的实用工具,属于 `<unistd.h>` 头文件。它帮助程序识别以 `-` 或 `--` 开头的选项(如 `-h`、`-o file`),并支持以下功能: --- ### **核心功能** 1. **短选项解析** - 支持单字符选项(如 `-a`, `-b`) - 支持带参数的选项(如 `-o value` 或 `-ovalue`) - 支持选项分组(如 `-abc` 等效于 `-a -b -c`) 2. **错误处理** - 自动检测未定义的选项 - 处理缺失的参数 --- ### **函数原型** ```c #include <unistd.h> int getopt(int argc, char *const argv[], const char *optstring); ``` - **参数说明**: - `argc`:主函数的参数个数(`main` 函数的 `argc`) - `argv`:主函数的参数字符串数组(`main` 函数的 `argv`) - `optstring`:定义合法选项的字符串(格式见下文) --- ### **optstring 格式** - **单个字符**:合法选项(如 `"a"` 表示 `-a`) - **字符后加 `:`**:选项需要参数(如 `"o:"` 表示 `-o value`) - **字符后加 `::`**:选项参数可选(GNU 扩展,非 POSIX 标准) 示例:`"ab:c::"` 表示: - `-a`(无参数) - `-b value`(必须带参数) - `-c` 或 `-cvalue`(参数可选) --- ### **关键全局变量** - `optarg`:指向当前选项参数的指针(如 `-o file` 中的 `file`) - `optind`:下一个待处理的 `argv` 索引 - `opterr`:是否输出错误信息(默认 `1`,设为 `0` 可禁用) - `optopt`:存储未识别的选项字符 --- ### **使用步骤** 1. **定义选项规则** ```c char *optstring = "hvo:"; // h: 帮助; v: 版本; o: 输出文件(需参数) ``` 2. **循环解析选项** ```c #include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { int opt; char *output_file = NULL; while ((opt = getopt(argc, argv, "hvo:")) != -1) { switch (opt) { case 'h': printf("Usage: %s [-h] [-v] [-o file]\n", argv[0]); return 0; case 'v': printf("Version 1.0\n"); return 0; case 'o': output_file = optarg; printf("Output file: %s\n", output_file); break; case '?': fprintf(stderr, "Unknown option: -%c\n", optopt); return 1; default: fprintf(stderr, "Error\n"); return 1; } } // 处理剩余非选项参数(argv[optind] 开始) for (int i = optind; i < argc; i++) { printf("Non-option argument: %s\n", argv[i]); } return 0; } ``` --- ### **常见问题** 1. **选项参数获取** - 必须使用 `optarg` 获取参数(如 `-o file` 中 `optarg` 指向 `"file"`) 2. **错误处理** - 当 `getopt` 返回 `?` 时,检查 `optopt` 以确定非法选项 3. **非选项参数** - 解析结束后,剩余参数通过 `argv[optind]` 到 `argv[argc-1]` 访问 --- ### **扩展知识** - **`getopt_long`**:支持长选项(如 `--help`),需 `<getopt.h>`,语法更复杂 - **`argp`**:GNU 高级参数解析库,适合复杂场景 --- 通过 `getopt`,可以高效地实现符合 Unix 惯例的命令行工具。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值