getopt函数实现命令行选项解析

使用getopt函数实现命令行选项解析

在编写程序时,我们经常需要处理命令行参数。getopt函数是一个强大的工具,用于解析命令行选项。在本教程中,我们将学习如何使用getopt函数为我们的程序添加灵活的命令行接口。

基础知识

首先,让我们定义我们的程序需求:一个名为mydate的程序,可以输出年月日,同时支持选项-y-m-d-H-M-S

命令行选项

每个命令行选项由一个字符组成,后面可以跟着一个或多个参数。例如,-y 2表示两位数的年份。getopt函数的optstring参数定义了可用的选项。

修改代码

我们从头开始编写代码,首先包含必要的头文件,并定义TIMESTRSIZE变量。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <locale.h>

#define TIMESTRSIZE 1024

int main()
{
    time_t stamp;
    struct tm *tm;
    char timestr[TIMESTRSIZE];
    
    // 获取当前时间
    time(&stamp);
    tm = localtime(&stamp);
    
    // 初始化时间字符串
    strftime(timestr, TIMESTRSIZE, "Now:", tm);
    
    // ... 省略了getopt函数的使用和解析逻辑 ...
    
    printf("%s\n", timestr);
    return 0;
}

接下来,我们添加getopt函数的调用,并处理不同的选项。

// 在命令行解析之前,设置默认区域
setlocale(LC_ALL, "");

int main(int argc, char **argv)
{
    time_t stamp;
    struct tm *tm;
    char timestr[TIMESTRSIZE];
    int c;
    
    // 获取当前时间
    time(&stamp);
    tm = localtime(&stamp);
    
    // 初始化时间字符串
    strftime(timestr, TIMESTRSIZE, "Now:", tm);
    
    // 解析命令行选项
    while ((c = getopt(argc, argv, "HMSyymdS:")) != -1) {
        switch (c) {
            case 'H': // 选项H,输出小时
                // 这里添加处理逻辑
                break;
            case 'M': // 选项M,输出分钟
                // 这里添加处理逻辑
                break;
            case 'S': // 选项S,输出秒
                // 这里添加处理逻辑
                break;
            case 'y': // 选项y,输出年份
                // 检查选项是否带有参数
                if (optarg) {
                    // 解析年份参数
                    // 这里添加处理逻辑
                }
                break;
            case 'm': // 选项m,输出月份
                // 这里添加处理逻辑
                break;
            case 'd': // 选项d,输出日
                // 这里添加处理逻辑
                break;
            default:
                printf("Invalid option: %c\n", c);
                break;
        }
    }
    
    // 打印最终的时间字符串
    printf("%s\n", timestr);
    return 0;
}

在以上代码中,我们仅仅是为了展示如何使用getopt函数进行了选项的循环处理,但在实际的选项处理逻辑中,你需要根据选项的要求进行相应的字符串格式化或输出。

处理带参数的选项

对于带参数的选项,如-y,你需要检查optarg是否为空,并据此进行处理。

case 'y':
    if (optarg) {
        // 假设我们想要输出4位或2位年份
        if (strcmp(optarg, "4") == 0) {
            strftime(timestr + strlen(timestr), TIMESTRSIZE - strlen(timestr), "%Y", tm);
        } else if (strcmp(optarg, "2") == 0) {
            strftime(timestr + strlen(timestr), TIMESTRSIZE - strlen(timestr), "%y", tm);
        } else {
            fprintf(stderr, "Invalid argument for -y: %s\n", optarg);
        }
    }
    break;

处理非选项参数

getopt函数在遇到非选项参数时,会返回-1,这时我们可以退出选项解析循环。

// ... 其他代码 ...

// 处理非选项参数
if (optind < argc) {
    // 这里可以处理非选项参数
    // 例如,打印非选项参数列表
    for (int i = optind; i < argc; i++) {
        printf("Non-option argument: %s\n", argv[i]);
    }
}

// ... 其他代码 ...

完整的示例代码

下面是一个完整的示例代码,包括了处理选项和参数的逻辑。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <locale.h>

#define TIMESTRSIZE 1024

int main(int argc, char **argv)
{
    setlocale(LC_ALL, "");

    time_t stamp;
    struct tm *tm;
    char timestr[TIMESTRSIZE];
    int c;

    // 获取当前时间
    time(&stamp);
    tm = localtime(&stamp);

    // 初始化时间字符串
    strftime(timestr, TIMESTRSIZE, "Now:", tm);

    // 解析命令行选项
    while ((c = getopt(argc, argv, "HMSyymdS:")) != -1) {
        switch (c) {
            case 'H': // 选项H,输出小时
                // 这里添加处理逻辑
                break;
            case 'M': // 选项M,输出分钟
                // 这里添加处理逻辑
                break;
            case 'S': // 选项S,输出秒
                // 这里添加处理逻辑
                break;
            case 'y': // 选项y,输出年份
                if (optarg) {
                    if (strcmp(optarg, "4") == 0) {
                        strftime(timestr + strlen(timestr), TIMESTRSIZE - strlen(timestr), "%Y", tm);
                    } else if (strcmp(optarg, "2") == 0) {
                        strftime(timestr + strlen(timestr), TIMESTRSIZE - strlen(timestr), "%y", tm);
                    } else {
                        fprintf(stderr, "Invalid argument for -y: %s\n", optarg);
                    }
                }
                break;
            case 'm': // 选项m,输出月份
                // 这里添加处理逻辑
                break;
            case 'd': // 选项d,输出日
                // 这里添加处理逻辑
                break;
            default:
                printf("Invalid option: %c\n", c);
                break;
        }
    }

    // 打印最终的时间字符串
    printf("%s\n", timestr);

    // 处理非选项参数
    if (optind < argc) {
        for (int i = optind; i < argc; i++) {
            printf("Non-option argument: %s\n", argv[i]);
        }
    }

    return 0;
}

完整的mydate程序

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

#define FMTSTRSIZE 255
#define TIMESTRSIZE 1024

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

    // 获取当前时间
    stamp = time(NULL);
    tm = localtime(&stamp);

    // 解析命令行选项
    while (1) {
        c = getopt(argc, argv, "-H:MSy:md"); // getopt会返回选项字符,如果是-后面跟数字则是1
        if (c < 0)
            break;

        switch (c) {
            case 1:
                fp = fopen(argv[optind - 1], "w"); // optind储存读到第几个参数的下标,读到文件地址时返回1,然后optind指向了下一个,所有要减一就是文件地址的参数
                if (fp == NULL) {
                    perror("fopen()");
                    fp = stdout;
                }
                break;
            case 'H': // 小时,24小时制
                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': // 年份
                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:
                fprintf(stderr, "Invalid option: %c\n", optopt);
                return 1;
        }
    }

    // 初始化时间字符串
    strncat(fmtstr, "\n", FMTSTRSIZE); // fputs不会自动换行,加个\n
    strftime(timestr, TIMESTRSIZE, fmtstr, tm);
    fputs(timestr, fp);

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

    exit(0);
}
  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成了大锦鲤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值