Linux 命令行程序的参数识别

引言

  我们几乎都是从 Windows 的操作开始学习计算机的,我第一次接触计算机是在初中的时候,当时学校机房安放的都是大块头,搭配经典的XP系统,俨然就是那个时代我对计算机的全部认识。之后很长一段时间,我也一直认为:“哦,电脑这东西,不就是在 Windows 上点来点去吗”?直到大学偶然的机会,我接触了 Linux 系统,才恍然大悟,要是我从一开始就用 Linux 学习计算机那该多好呀!

  很多人觉得 Linux 很难,因为没有漂亮的图形界面,要背很多命令,然后一个个去敲才能完成任务。这让我想起了一个道理:

很久很久以前,谎言和真实在河边洗澡。
谎言先洗好,穿了真实的衣服离开了!真实却不肯穿谎言的衣服。
后来,在人们的眼里,只有穿着真实衣服的谎言,却很难接受赤裸裸的真实。

  很多人只喜欢操作漂亮的图形界面,却很难接受在终端敲命令行。
  比如,在我们公司,很多同事和领导深受 Windows 毒害,通常我开发完某个工具或者新功能时,他们都要求我集成到图形界面上方便他们操作。我内心是拒绝的,但是为了那点钱,还是通过 Qt、Python,亦或 Web 的方式给他们展示出来了。这样的好处就是,我学会了很多技能包。。。当然,领导和同事们还是很开心的,毕竟这是他们最喜欢的谎言!此话不假,因为他们所看到的都是经过我包装的,而真实赤裸裸地躺在终端里,他们却不曾看见。


概述

  不用多说,我们都知道命令行对于 Linux 来说有多么重要,而大部分的命令行程序都是带参数的,例如 ls、cd、mount 等等。同样,如果我们自己开发命令行程序,也会通过参数使程序变得更加灵活和通用。
  下面我们来看看在 Linux C 编程中如何支持参数以及对参数进行识别。
  还记得 main 函数吗?它在 Linux 里面一般会这样定义:

int main(int argc, char *argv[])
{
    // do something
    return 0;
}

  我们通过 main 函数的参数 argc 和 argv 就可以获取并处理通过命令行传入的参数了,对于参数较少的命令行程序,我们自己解析就可以了。但是,如果参数较多,自己解析的话很容易使代码变得臃肿,而且也不利于代码重用。那该怎么办呢?
  答案就是 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);
描述:getopt 是用来解析命令行选项参数的,但是只能解析短选项(如 -d 100),不能解析长选项(如 –prefix)
参数

  • argc:main() 函数传递过来的参数的个数
  • argv:main() 函数传递过来的参数的字符串指针数组
  • optstring:选项字符串,告知 getopt() 可以处理哪个选项以及哪个选项需要参数

返回:如果选项成功找到,返回选项字母;如果所有命令行选项都解析完毕,返回 -1;如果遇到选项字符不在 optstring 中,返回字符 '?';如果遇到丢失参数,那么返回值依赖于 optstring 中第一个字符,如果第一个字符是 ':' 则返回 ':',否则返回 '?' 并提示出错误信息。

下面说明 optstring 的格式意义:

char*optstring = “ab:c::”;

单个字符 a  表示选项 a 没有参数;格式:-a 即可,不加参数。
单字符加冒号 b: 表示选项 b 有且必须加参数;格式:-b 100 或 -b100,但 -b=100 是错误的。
单字符加两冒号 c:: 表示选项 c 的参数可以有,也可以没有;格式:-c200,其它格式错误。

  上面这个 optstring 在传入之后,getopt 函数将依次检查命令行是否指定了 -a,-b,-c(这需要多次调用 getopt 函数,直到其返回 -1),当检查到上面某一个参数被指定时,函数会返回被指定的参数名称(即该字母)。
  此外,还有几个重要的全局变量:

  • optarg —— 指向当前选项参数(如果有)的指针。
  • optind —— 再次调用 getopt() 时的下一个 argv 指针的索引。
  • optopt —— 最后一个未知选项。
  • opterr ­——如果不希望 getopt() 打印出错信息,则只要将全局变量 opterr 设为 0 即可。

getopt_long 函数

  下面再说说 getopt_long 函数,getopt_long 函数包含了 getopt 函数的功能,另外允许指定“长参数”(或者说长选项),与 getopt 函数对比,getopt_long 比其多了两个参数。

定义int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts,int *longindex);
描述:包含 getopt 功能,增加了解析长选项的功能(如:–prefix –help)
参数

  • longopts:指明了长参数的名称和属性
  • longindex:如果 longindex 非空,它指向的变量将记录当前找到参数符 longopts 里的第几个元素的描述,即是 longopts 的下标值

返回:对于短选项,返回值同 getopt 函数;对于长选项,如果 flag 是NULL,返回 val,否则返回 0;对于错误情况返回值同 getopt 函数。

结构体

struct option {
    const char  *name;       /* 参数名称 */  
    int          has_arg;    /* 指明是否带有参数 */  
    int          *flag;      /* flag=NULL时,返回value;不为空时,*flag=val,返回0 */  
    int          val;        /* 用于指定函数找到选项的返回值或flag非空时指定*flag的值 */  
};  

has_arg 指明是否带参数值,其数值可选:

  • no_argument:表明长选项不带参数,如:--name--help
  • required_argument:表明长选项必须带参数,如:--prefix /root--prefix=/root
  • optional_argument:表明长选项的参数是可选的,如:--help–prefix=/root,其它都是错误。

getopt_long_only 函数

  getopt_long_only 函数与 getopt_long 函数使用相同的参数表,在功能上基本一致,只是 getopt_long 只将 –name 当作长参数,但 getopt_long_only 会将 –name 和 -name 两种选项都当作长参数来匹配。getopt_long_only 如果选项 -name 不能在 longopts 中匹配,但能匹配一个短选项,它就会解析为短选项。

猜你喜欢

转载自blog.csdn.net/luckydarcy/article/details/80502186