【Linux 命令行参数解析函数getopt()】原理及直白理解

最近写代码恰好碰见getopt()这个函数,去网上找了很久,说实话,其他人写的有点看不懂,所以将我认为可以便于理解的地方描述一下:

c 复制代码
int getopt(int argc, char * const argv[], const char *optstring);

首先理解这个函数的功能(不能保证大家都能理解)

  1. 获取命令行信息,并读取命令行中的选项;

    (命令行组成或许存在盲区,这是某位博主的这是他的博客

    Option就是选项,Option argument是参数:

  2. 每读取到一个选项,会返回一个int整型 ,这个整型不是选项位置,而是选项对应的ASCII码值

  3. 这个函数附带了一些全局变量,这些全局变量中的optarg 会对应着解析到的某个选项对应的参数

其次我们需要理解函数原型

该函数的参数说明如下:

argc(参数个数):
  1. 类型:int
  2. 说明:这是从main函数传递过来的命令行参数个数。在C语言中,argc包含了程序名(即argv0),因此如果命令行中有3个参数(不包括程序名),则argc的值为4。
argv(参数内容):
  1. 类型:char * const argv\[\]
  2. 说明:这是从main函数传递过来的命令行参数数组。argv是一个指向指针的指针,每个指针指向一个C风格的字符串(以null字符\0结尾)。argv0通常是程序的名称,随后的元素是传递给程序的命令行参数。
optstring(选项字符串):
  1. 类型:const char *
  2. 说明:这是一个字符串,它定义了getopt函数可以识别的选项。选项字符串中的每个字符都代表一个有效的选项。如果某个选项字符后面跟着一个冒号(:),则表示该选项需要一个参数。如果字符后面跟着两个冒号(::),则表示该选项的参数是可选的。
getopt函数的返回值主要有以下几种情况:
  1. 选项字符:当成功解析一个选项时,getopt返回该选项的字符(实际上是其ASCII码值,但通常直接作为字符使用)。
  2. EOF或-1:当所有选项都解析完毕后,getopt返回EOF(在POSIX系统中,EOF通常定义为-1)。这表示没有更多的选项需要处理。
  3. '?':如果遇到不符合optstring指定的选项,并且opterr未被设置为0,getopt会打印一个错误消息,并返回'?'字符。这通常用于表示未知的选项。

getopt函数的全局变量:

  1. optarg:指向当前选项参数的指针(如果有的话)。
  2. optind:再次调用getopt时的下一个argv指针的索引。
  3. opterr:如果设置为0,则getopt不会打印错误消息。
  4. optopt:最后一个未知选项。

getopt函数的行为:

  1. 当成功解析一个选项时,返回该选项的字符(实际上是其ASCII码值,但通常直接作为字符使用)。
  2. 当所有选项都解析完毕后,返回-1或EOF。
  3. 如果遇到不符合optstring指定的选项,getopt将显示一个错误消息(除非opterr被设置为0),并将optopt设为?字符。

getopt参数示例(这个案例很清晰,如果要做大总结,我觉得这个函数的名称其实就足够:命令行参数解析函数)

假设我们有以下optstring:"ab:c::de",并考虑以下命令行参数:

bash 复制代码
./program -a -b argb --c=argc -d -e arge foo bar

在C程序中,我们可能会这样使用getopt:

c 复制代码
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
  
int main(int argc, char *argv[]) {  
    int opt;  
    while ((opt = getopt(argc, argv, "ab:c::de")) != -1) {  
        switch (opt) {  
        case 'a':  
            printf("Option -a\n");  
            break;  
        case 'b':  
            printf("Option -b with argument '%s'\n", optarg);  
            break;  
        case 'c':  
            // 注意:如果选项c后面有参数,它必须紧跟在c后面  
            if (optarg) {  
                printf("Option -c with argument '%s'\n", optarg);  
            } else {  
                printf("Option -c (no argument)\n");  
            }  
            break;  
        case 'd':  
            printf("Option -d\n");  
            break;  
        case 'e':  
            // 注意:选项e后面的'arge'不是选项e的参数,而是非选项参数  
            printf("Option -e\n");  
            break;  
        case '?':  
            // getopt会打印错误消息,但我们也可以在这里添加自定义处理  
            fprintf(stderr, "Unknown option: %c\n", optopt);  
            exit(EXIT_FAILURE);  
        default:  
            abort(); // 其他情况下,应该不会发生  
        }  
    }  
  
    // optind现在是第一个非选项参数的索引  
    // 在这个例子中,它是"foo"的索引  
    for (int i = optind; i < argc; i++) {  
        printf("Non-option argument: %s\n", argv[i]);  
    }  
  
    return 0;  
}

运行上面的程序,输出将会是:

bash 复制代码
Option -a  
Option -b with argument 'argb'  
Option -c (no argument) // 因为-c后面没有直接跟随参数  
Option -d  
Option -e  
Non-option argument: foo  
Non-option argument: bar

注意,尽管命令行中包含--c=argc这样的长选项格式,但getopt只处理短选项(单个字符的选项)。如果你需要处理长选项,可能需要使用getopt_long函数或手动解析它们。

相关推荐
forestsea24 分钟前
从零构建 Java 智能体 RAG 系统:Milvus 向量数据库实战指南
java·数据库·milvus
码农小韩43 分钟前
Linux应用开发(八)——TCP/IP网络编程基础
linux·嵌入式软件开发·linux操作系统·嵌入式操作系统·linux网络编程·linux应用
迷途之人不知返1 小时前
【进程】-5-进程优先级
linux
probex_1 小时前
从 ByConity 到 VictoriaMetrics:一次指标数据迁移引发的四种存储对比
数据库
fengyehongWorld1 小时前
Linux squid搭建基础代理服务器
linux·运维·服务器
木白CPP1 小时前
Linux DMA驱动详解(二)-----DMA的使用者
java·linux·运维
Patrick在香港2 小时前
Python 审计香港开放数据目录:两个端点差 10 倍,只有 9.3% 的资源标了「最后修改时间」
开发语言·数据库·python·数据分析·api·数据治理·开放数据
这个DBA有点耶2 小时前
自增主键用尽了怎么办?INT溢出、在线迁移与预防策略全解析
数据库·mysql·代码规范
赵民勇2 小时前
systemd-socket-activate命令详解
linux·运维
老纪的技术唠嗑局2 小时前
Agent 习惯性删库跑路,数据库纷纷学 Git 续命
数据库·人工智能