Linux:linux getopt_long()函数(命令行解析)(getopt、getopt_long_only)(短选项 -,长选项 --)

前言

linux中,经常需要各种命令,通常情况下都会带各种参数,而这些参数是如何解析的呢?通常使用GNU C提供的函数getopt、getopt_long、getopt_long_only函数来解析命令行参数。

一、关于命令行参数

命令行参数可以分为两类,一类是短选项,一类是长选项,短选项在参数前加一杠"-",长选项在参数前连续加两杠"--",如下表(ls 命令参数)所示,其中-a,-A,-b都表示短选项,--all,--almost-all, --author都表示长选项。他们两者后面都可选择性添加额外参数。比如--block-size=SIZE,SIZE便是额外的参数。例如:

LS(1) User Commands LS(1)

NAME

ls - list directory contents

SYNOPSIS

ls [OPTION]... [FILE]...

DESCRIPTION

List information about the FILEs (the current directory by default).

Sort entries alphabetically if none of -cftuvSUX nor --sort is speci‐

fied.

Mandatory arguments to long options are mandatory for short options

too.

-a, --all

do not ignore entries starting with .

-A, --almost-all

do not list implied . and ..

--author

with -l, print the author of each file

-b, --escape

print C-style escapes for nongraphic characters

--block-size=SIZE

scale sizes by SIZE before printing them; e.g., '--block-size=M'

prints sizes in units of 1,048,576 bytes; see SIZE format below

-B, --ignore-backups

do not list implied entries ending with ~

二、getopt_long函数

getopt函数只能处理短选项,而getopt_long函数两者都可以,可以说getopt_long已经包含了getopt的功能。因此,这里就只介绍getopt_long函数。而getopt_long与getopt_long_only的区别很小,等介绍完getopt_long,再提起会更好。

#include <unistd.h>

extern char *optarg;

extern int optind, opterr, optopt;

#include <getopt.h>

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

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

参数以及返回值介绍(以上三个函数都适用):
1、argc和argv和main函数的两个参数一致。
2、optstring: 表示短选项字符串。

形式如"a:b::cd:",分别表示程序支持的命令行短选项有-a、-b、-c、-d,冒号含义如下:

(1)只有一个字符,不带冒号------只表示选项, 如-c

(2)一个字符,后接一个冒号------表示选项后面带一个参数,如-a 100

(3)一个字符,后接两个冒号------表示选项后面带一个可选参数,即参数可有可无, 如果带参数,则选项与参数之间不能有空格

形式应该如-b200

3、longopts:表示长选项结构体。结构如下:

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 }

};

(1)name:表示选项的名称,比如daemon,dir,out等。

(2)has_arg:表示选项后面是否携带参数。该参数有三个不同值,如下:

a: no_argument(或者是0)时 ------参数后面不跟参数值,eg: --version,--help

b: required_argument(或者是1)时 ------参数输入格式为:--参数 值 或者 --参数=值。eg:--dir=/home

c: optional_argument(或者是2)时 ------参数输入格式只能为:--参数=值

(3)flag:这个参数有两个意思,空或者非空。

a:如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。

eg,可执行程序 --help,getopt_long的返回值为h.

b:如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。

eg: 可执行程序 --http-proxy=127.0.0.1:80 那么getopt_long返回值为0,并且lopt值为1。

(4)val:表示指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值val。

4、longindex:longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值。
5、全局变量:

(1)optarg:表示当前选项对应的参数值。

(2)optind:表示的是下一个将被处理到的参数在argv中的下标值。

(3)opterr:如果opterr = 0,在getopt、getopt_long、getopt_long_only遇到错误将不会输出错误信息到标准输出流。opterr在非0时,向屏幕输出错误。

(4)optopt:表示没有被未标识的选项。

6、返回值:

(1)如果短选项找到,那么将返回短选项对应的字符。

(2)如果长选项找到,如果flag为NULL,返回val。如果flag不为空,返回0

(3)如果遇到一个选项没有在短字符、长字符里面。或者在长字符里面存在二义性的,返回"?"

(4)如果解析完所有字符没有找到(一般是输入命令参数格式错误,eg: 连斜杠都没有加的选项),返回"-1"

(5)如果选项需要参数,忘了添加参数。返回值取决于optstring,如果其第一个字符是":",则返回":",否则返回"?"。

注意:

(1)longopts的最后一个元素必须是全0填充,否则会报段错误

(2)短选项中每个选项都是唯一的。而长选项如果简写,也需要保持唯一性。

三、测试(自行测试)(getopts配合case来进行操作时有两个隐含变量:一个是OPTARG,用来取当前选项的值,另外一个是OPTIND,代表下一个要处理的元素位置。)

1、官网给出测试用例。

复制代码
#include <stdio.h>     /* for printf */
#include <stdlib.h>    /* for exit */
#include <getopt.h>
 
int main(int argc, char **argv)
{
    int c;
    int digit_optind = 0;
 
   while (1) {
        int this_option_optind = optind ? optind : 1;
        int option_index = 0;
        static struct option long_options[] = {
            {"add",     required_argument, 0,  0 },
            {"append",  no_argument,       0,  0 },
            {"delete",  required_argument, 0,  0 },
            {"verbose", no_argument,       0,  0 },
            {"create",  required_argument, 0, 'c'},
            {"file",    required_argument, 0,  0 },
            {0,         0,                 0,  0 }
        };
 
       c = getopt_long(argc, argv, "abc:d:012",
                 long_options, &option_index);
        if (c == -1)
            break;
 
       switch (c) {
        case 0:
            printf("option %s", long_options[option_index].name);
            if (optarg)
                printf(" with arg %s", optarg);
            printf("\n");
            break;
 
       case '0':
       case '1':
       case '2':
            if (digit_optind != 0 && digit_optind != this_option_optind)
              printf("digits occur in two different argv-elements.\n");
            digit_optind = this_option_optind;
            printf("option %c\n", c);
            break;
 
       case 'a':
            printf("option a\n");
            break;
 
       case 'b':
            printf("option b\n");
            break;
 
       case 'c':
            printf("option c with value '%s'\n", optarg);
            break;
 
       case 'd':
            printf("option d with value '%s'\n", optarg);
            break;
 
       case '?':
            break;
 
       default:
            printf("?? getopt returned character code 0%o ??\n", c);
        }
    }
 
   if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }
 
   exit(EXIT_SUCCESS);
}

运行结果:

root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]23# ./a.out -0 option 0 \[root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]24# ./a.out -1 option 1 \[root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]25# ./a.out -2 option 2 \[root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]26# ./a.out -a option a \[root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]27# ./a.out -b option b \[root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]28# \[root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]28# ./a.out -c100 option c with value '100' \[root@ubuntu /home/yg/arnold_test/20211129_TEST_getopt\]29# ./a.out -d333 option d with value '333'

参考

Example of Parsing Long Options with getopt_long

相关推荐
赖small强12 分钟前
【Linux 网络基础】HTTPS 技术文档
linux·网络·https·tls
写代码的学渣38 分钟前
ubuntu 22.04 新装的系统 xshell 连不上
linux·运维·ubuntu
序属秋秋秋1 小时前
《Linux系统编程之进程环境》【环境变量】
linux·运维·服务器·c语言·c++·操作系统·系统编程
Yue丶越1 小时前
【C语言】数据在内存中的存储
c语言·开发语言·网络
云计算练习生2 小时前
linux shell编程实战 10 Git工具详解与运维场景实战
linux·运维·git
虚伪的空想家4 小时前
KVM的ubuntu虚机如何关闭安全启动
linux·安全·ubuntu
t1987512810 小时前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk816310 小时前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate
Yue丶越10 小时前
【C语言】字符函数和字符串函数
c语言·开发语言·算法
晚风吹人醒.11 小时前
缓存中间件Redis安装及功能演示、企业案例
linux·数据库·redis·ubuntu·缓存·中间件