Linux 选项参数
为了增强应用程序的通用性和灵活性,软件设计师通常会把程序中可变的部分抽离出来,让程序本身只处理业务逻辑,实现配置参数与功能代码的解耦合。在 Linux 系统编程中,通常有两种做法:
- 通过配置文件与程序进行交互(ini、xml、json...)
- 通过命令行选项参数进行交互(getopt)
配置文件的格式可以是常见的 ini、xml、json 或 yaml,也可以是自定义的文件格式,对于配置项较多的程序,这种方式会更方便、更直观。而命令行选项参数在 Linux 更加常见,几乎所有 Linux 命令行工具都支持(例如 ls、cd、mount 等)。
不用多说,我们都知道命令行对于 Linux 来说有多么重要,而大部分的命令行程序都是带参数的。如果是我们自己开发的命令行程序,该怎么灵活方便地为其添加选项参数呢?下面我们来看看在 Linux C 编程中如何支持参数以及对参数进行识别!
命令行参数
命令行参数的管理
Linux 应用程序是从 main 函数开始执行的,如果需要带选项参数,通常会这么定义 main 函数:
int main(int argc, char *argv[])
{
// do something
return 0;
}
- 第1个参数 argc 表示参数的数目,包含命令本身,也就是说如果命令后面不带参数的话,argc 就等于 1。
- 第2个参数 argv 是字符指针数组,其成员依次指向各个参数,argv[0] 指向命令本身,argv[1] 指向后面带的第1个参数,指针数组最后一个成员为 NULL,表示参数结束。
比如 ls -w 80
命令,其进程启动之后拿到的 argc 和 argv 参数内容如下:
这里要区分一下命令、选项、参数的概念。它们以空格隔开,第一个就是命令(如果使用管道,一个命令行中可以包含多个命令);选项和参数通常都是可选的,选项分为短选项和长选项,比如这里的 -w
是短选项,它对应的长选项是 --width
;参数 80 是对前面的选项 -w
的描述,并非所有选项都有参数,具体由程序本身决定。参数可以紧跟选项,也可以用空格隔开,对于长选项参数还可以使用等号,所以下面几种写法是等效的:
ls -w 80
ls -w80
ls --width 80
ls --width=80
命令行参数的识别
理解了上面这点,显然我们要解析命令行的选项参数,只需要根据 main 函数传入的参数 argc 和 argv 就可以获取并处理通过命令行传入的参数了。但这样会增加程序员的工作量,并且命令行的选项参数通常是随意的,不会刻意让某个参数处于第 1 或者第 2 的位置。如果参数较多,自己解析的话很容易使代码变得臃肿,而且也不利于代码重用。那该怎么办呢?
答案就是 getopt 系列函数!通过 getopt 将参数解析部分解 耦出来,数据驱动的方式看起来也很美观,我们 man 一下看看:
#include<unistd.h>
int getopt(intargc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#include<getopt.h>
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);
从函数名字可以看出来,getopt_long 和 getopt_long_only 应该是 getopt 的增强版,我们先来看看最简单的 getopt 函数吧。
getopt 函数
定义:
int getopt(int argc, char * const argv[], const char *optstring);