看第21章时,介绍到了解析命令行的神器 getopt,了解了 linux 下处理通用命令行的方法。

命令行可分为参数与选项,其中不带 - 或 -- 前缀的为参数,对一个命令而言数量是固定的,多个参数之间的顺序也是固定的(不然命令没法区分);而选项就是带 - 或 -- 前缀的,可有可没有的,由用户的输入决定,另外选项也可以有自己的跟随参数,它们之间是没有顺序的。比如说:

> wget -c http://strawberryperl.com/download/5.30.2.1/strawberry-perl-5.30.2.1-32bit.msi

这个 wget 命令行有两个输入,一个是选项 -c,表示断点续传;一个是参数 url,就是后面这一串下载的地址。

当然这只是一个简单的例子,并没有多个参数,也没有多个选项,选项也没有带自己的参数。后面我们会自己做一个复杂的例子,来做验证。

回到 getopt,它的作用就是简化对这些输入的处理。

如何简化呢,就是通过定义一个可接受的选项“模板”,然后通过不停调用 getopt 来将所有选项解析出来,

最后剩下的就是不能被识别的参数了,但是这种场景就简单了,只需按顺序处理它们即可。

下面是一个用来作验证的例子:

getopt.c

 #include "../apue.h"
int main (int argc, char *argv[])
{
int c, i;
char fmt[] = { };
char *abc = "abcdefghijklmnopqrtsuvwxyz";
char *ABC = "A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z:";
strcat (fmt, abc);
strcat (fmt, ABC);
while ((c = getopt (argc, argv, fmt)) != -) {
printf ("got option [%d]: '%c' ('%c')", optind, c, optopt);
if (optarg)
printf (" arg: '%s'", optarg); printf ("\n");
} printf ("end up at %d\n", optind);
if (optind < argc)
printf ("some argument left, from %s\n", argv[optind]);
exit ();
}

这个例子比较“贪心”,定义了所有的字母做选项,其中小写字母不带参数,大写字母均带参数。最后打印解析不了的参数。

它可以用来验证 getopt 有没有正确的执行:

$ ./getopt -a -b -c -A 1 -B 2 -C 3 admin 123qwe
got option [2]: 'a' ('')
got option [3]: 'b' ('')
got option [4]: 'c' ('')
got option [6]: 'A' ('') arg: '1'
got option [8]: 'B' ('') arg: '2'
got option [10]: 'C' ('') arg: '3'
end up at 10
some argument left, from admin

打印了一些 getopt 相关设施 (optind/optarg/optopt) 的返回值,以便可以观察它们随着选项解析后的变化。

其中中括号中的是 optind 代表的值,表示下一个输入在 argv 中的位置。

当所有选项解析完成后,这个位置将被更新到结尾或第一个参数的位置(如果有)。

我一直有个疑问,如果当参数夹杂在选项中时,这个位置是定位到哪里呢?

如果定位到那个参数的位置,那么应用在向后遍历剩余参数时,岂不是会遍历到已经解析的选项?

如果不是,那岂不是漏掉了一个参数?

于是我用这个小程序做了个测试,就像这样:

$ ./getopt -a -b admin -c -A 1 -B 2 123qwe -C 3
got option [2]: 'a' ('')
got option [3]: 'b' ('')
got option [5]: 'c' ('')
got option [7]: 'A' ('') arg: '1'
got option [9]: 'B' ('') arg: '2'
got option [12]: 'C' ('') arg: '3'
end up at 10
some argument left, from admin

这次我把用户名参数放在了 -b 与 -c 之间,把密码参数放在了 -B 与 -C 之间。

可以看到,各个选项都解析出来了,没有漏掉;而参数貌似也是正确的。

等等,这个optind显示位置是 argv[10],也就是说 admin 位于 argv[10],但是明明它是 argv[3] 啊!

而且解析完 -C 时 optind 已经到了 12 就是结尾了,怎么最后又倒回去了?

为了解释这种种谜团,在解析完成后加入以下两句代码,打印解析后的命令行:

     for (i = ; i<argc; ++ i)
printf ("%s ", argv[i]); printf ("\n");

新的程序执行输出如下:

$ ./getopt -a -b admin -c -A 1 -B 2 123qwe -C 3
got option [2]: 'a' ('')
got option [3]: 'b' ('')
got option [5]: 'c' ('')
got option [7]: 'A' ('') arg: '1'
got option [9]: 'B' ('') arg: '2'
got option [12]: 'C' ('') arg: '3'
end up at 10
./getopt -a -b -c -A 1 -B 2 -C 3 admin 123qwe
some argument left, from admin

原来是命令行参数顺序被重新排列了。

所有选项经过解析后排在了参数之前,而参数保持输入时的顺序被排列在选项后面。

这样通过 optind 进行遍历,就会得到原顺序的参数输入,perfect !

通过 man 3 getopt 也发现了这样描述:

       By  default, getopt() permutes the contents of argv as it scans, so that eventually
all the non-options are at the end.

其它的谜团也迎刃而解。

其实回过头来想,这种 permute argv 参数的成本几乎没有,就是移动几个指针的指向而已,可以说用最小的代价完成了最大的收益。

当然了,getopt 也不是万能的,例如在选项中有重复的输入时,就需要你来处理它们了(不做特别处理的话是后面的选项覆盖前面的)。

[apue] getopt 可能重排参数的更多相关文章

  1. python 使用getopt 获取配置参数

    在工程中特别是稍微大一点的项目基本上都会用到配置,就会涉及到配置文件的读取,配置参数的读取. 常用的解析配置文件的是configParser,解析命令行参数的则为getopt. getopt的参数可以 ...

  2. [转载]函数getopt(),及其参数optind

    最近用到了getopt()这个函数,对它进行了一些了解.这篇博文还是写的非常清楚的.值得学习.最近在改进一个开源项目,希望自己能静下心好好分析代码. ------------------------- ...

  3. 如何使用getopt()函数解析参数

    最近在写程序的过程中,把一部分时间都花费在程序对参数的处理上.今天听了学长说到getopt函数,才发现原来c里面还有一个专门解决参数处理的函数,查询了相关资料,这里简单总结一下. 使用int main ...

  4. getopt和getopt_long参数处理

    1:getopt函数 getopt主要用于解析程序运行时所带的参数,原型如下: #include <unistd.h> int getopt(int argc, char * const ...

  5. 使用 getopt 处理命令行长参数

    getopt命令并不是bash的内建命令,它是由util-linux包提供的外部命令. getopt 与 getopts 的区别 getopts 是 shell 内建命令, getopt 是一个独立外 ...

  6. Shell 参数(2) --解析命令行参数工具:getopts/getopt

    getopt 与 getopts 都是 Bash 中用来获取与分析命令行参数的工具,常用在 Shell 脚本中被用来分析脚本参数. 两者的比较 (1)getopts 是 Shell 内建命令,geto ...

  7. 自学Linux Shell13.2-选项处理(主要getopt、getopts命令)

    点击返回 自学Linux命令行与Shell脚本之路 Bash shell提供了一些不同的方法来从用户处获得数据,包括以下3中方法: 命令行参数(添加在名利后面的数据) 命令行选项(可修改命令行为的单个 ...

  8. getopts的使用

    getopts的使用 语法格式:getopts [option[:]] [DESCPRITION] VARIABLE option:表示为某个脚本可以使用的选项 ":":如果某个选 ...

  9. [Perl] Getopt 函数来接收用户参数的使用

    我们在linux常常用到一个程序需要加入参数,现在了解一下perl中的有关控制参数的函数.getopt.在linux有的参数有二种形式.一种是–help,另一种是-h.也就是-和–的分别.–表示完整参 ...

随机推荐

  1. apache 自带的ab.exe 测试网站的并发量(网站压力测试)

    AB(ApacheBench) 是 Apache 自带的超文本传输协议 (HTTP) 性能测试工具. 其设计意图是描绘当前所安装的 Apache 的执行性能, 主要是显示 Apache 每秒可以处理多 ...

  2. C 实战练习题目3

    题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少? 程序分析: 假设该数为 x. 1.则:x + 100 = n2, x + 100 + 168 = m2 ...

  3. OpenCV-Python 图像阈值 | 十五

    目标 在本教程中,您将学习简单阈值,自适应阈值和Otsu阈值. 你将学习函数cv.threshold和cv.adaptiveThreshold. 简单阈值 在这里,问题直截了当.对于每个像素,应用相同 ...

  4. PySpark初级教程——第一步大数据分析(附代码实现)

    概述 数据正以前所未有的速度与日俱增 如何存储.处理和使用这些数据来进行机器学习?spark正可以应对这些问题 了解Spark是什么,它是如何工作的,以及涉及的不同组件是什么 简介 我们正在以前所未有 ...

  5. 学习Angular1

    教程: 参考教程: https://www.runoob.com/angularjs/angularjs-tutorial.html 一.angular的简介AngularJS 是一个 JavaScr ...

  6. python ——钟表

    1.表盘 from turtle import * from datetime import * def Skip(step):#表盘不连续地画图 penup() forward(step) pend ...

  7. Java并发基础03. 传统线程互斥技术—synchronized

    在多个线程同时操作相同资源的时候,就会遇到并发的问题,如银行转账啊.售票系统啊等.为了避免这些问题的出现,我们可以使用synchronized关键字来解决,下面针对synchronized常见的用法做 ...

  8. SpringMVC知识大览

    SpringMVC大览 springMVC的基础知识 什么是SpringMVC? springmvc框架原理(掌握) 前端控制器.'处理映射器.处理适配器.视图解析器 springmvc的入门程序 目 ...

  9. VM虚拟机复制文件问题

    需要安装好vmtools,安装好后,启动虚拟机环境: 把需要复制的文件拖进虚拟机环境窗口,鼠标指针会变成复制图标,直接左键即可复制: 不能Ctrl+c-Ctrl+v进去.

  10. BigDecimal 笔记

    参数 BigDecimal 类主要有如下几个参数 这几个参数都比较好理解,看过这两个例子基本都能明白,现在总结一下就是 scale // 小数点后位数 precision // 一共位数 intCom ...