命令行多参数解析时getopt()函数的使用方法小结
在Linux中,用命令行执行可执行文件时,常常涉及到:大量、不同类型、不同形式的 输入参数问题。从简单的说起,现在假设有我们一个用户定义的可执行程序,名为test.sh
,它需要3个输入参数,于是我们通过命令行去执行它的时候,往往通过如下的做法:
1 | ./test.sh 1 2 3 |
一. main函数
上面的./test.sh
是执行程序,1、2、3
是test.sh
的输入参数,这些命令项通过传递给程序的main函数进行处理,main函数的一般形式如下:
1 | int main(int argc, char *argv[]); |
argc是一个整型,argv是一个指针数组,argc记录argv的大小,例如./test.sh 1 2 3
将被以如下的方式传递:
1 | argc=4; |
二. getopt函数
现在我们考虑更复杂一些的输入要求,还是以test.sh
为例,不过这时它的输入参数要更多一些了
1 | ./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T // 此处仅作为示例,还可以有更多更复杂参数,见后续实例 |
先说说这一行参数表示什么意思,这里的破折号-
表示这是一个控制选项,例如-1
,在此处1是单字符选项,而-a 4
表示带参数的选项,a是该选项的标识符,4是随同该选项一同传入的参数,-Q
,与-1
一样,Q也是单字符选项,没有随同的输入参数。通过定义不同的选项,我们可以在test.sh
中定义丰富的操作完成各种各样的计算任务,但是这个时候main函数可没有办法给你完成上面的解析工作,main函数只是将./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T
传递进来,保存在argc和argv里,至于这些参数如何分配并对应什么操作则是需要用户自行定义了,当然,自己写解析函数是可行的,但是有更好的选择。
在C语言中,unistd.h
提供的getopt()
这个函数,结合switch
语句,可以帮助我们方便实现参数解析。
先看例子:
1 | …… |
getopt()函数原型为:
1 | int getopt(int argc, char * const argv[], const char *optstring); |
使用getopt函数需要包含以下头文件:
1 |
有几个全局变量与getopt函数解析参数有关:
optind:int型, 指示下一个要解析的参数位置,初始时为1。
optarg:char *, 必须接参数的选项元素的参数, optarg 就指向参数字符串。
opterr: int 型, 设为0将不打印错误信。
int argc, char * const argv[]
一般是直接通过读取main函数的argc和argv,而optstring则是用户定义的选项字符,例如在上面的例子中,optstring是 123a:b:c:QST
,它用来解析输入参数./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T
,并且是由用户定义。
字符串optstring的元素一般可分为下面几种:
- 单个字符,表示选项,
123a:b:c:QST
中的1、2、3、Q、S、T都是单字符选项 - 单个字符后接一个冒号
:
表示该选项后必须跟一个参数。参数紧跟在选项后以空格隔开。该参数的指针赋给optarg。123a:b:c:QST
中的a:
,b:
,c:
都表示它们需要附加指定输入参数,这就是为什么在输入参数时是-a 4 -b 5 -c 6
的缘故 - 单个字符后跟两个冒号
::
表示该选项后可选地跟一个参数。参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张,本例中不作介绍)。
update@2016年5月17日17:11:51
一个选项的识别符号只能是单个字符(或加上与一个冒号:
或两个冒号::
的组合),不能用多个字符来表示一个选项。
例如这样做就会识别出错:
用户输入的参数./test.sh -1 -2 -3 -a1 4 -b 5 -c 6 -Q -S -T
,那么它对应的optstring则是 123a1:b:c:QST
,显然其中a1
为两个字符,想让它表示一个选项,是会出现问题的。
同时,getopt()在unistd.h中的相关定义:
1 | * extern char *optarg; //选项的参数指针 |
那么现在就清楚用户输入的参数./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T
是怎么进行传递和解析的了:
- 通过main函数将输入参数
./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T
保存在argc和argv - getopt()按照
123a:b:c:QST
这个规则去解析argc和argv中保存的数据 - 例如,首先去
./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T
读取到的选项是-1
(第一个输入参数./test.sh是执行程序是名称不予考虑),于是就去123a:b:c:QST
中检查是否有1
这个选项,有的话就返回该选项(这个时候就会转入相应的case执行对应的操作),同时将选项索引optind更新为输入参数的下一个位置(此处为-2
的位置)作为下次搜索的开始位置,如果在optstring里没有找到1
,例如我们的optstring是23a:b:c:QST
,即当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt中,getopt返回'?'
,并从optind开始进行下一个输入参数的解析 继续解析,当解析到
-a
时,这个时候getopt()发现optstring里的a
后面跟着:
于是它知道a是还需要传递进来一个指定的参数,于是就将指针*optarg指向-a后面的一个参数即是4,这样返回选项a的时候,a所对应的参数值此时由optarg指向,这样转入case 'a'
的时候就可以对该参数进行相应的操作了1
2
3case 'a':
para4 = atof(optarg);
break;接着往下走,-Q -S -T与前面的-1是一样的,都是不带参数的单字符选择,当检查完-T后,返回-1,表示检查完毕,这个时候就完成了对
./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T
中所有参数的分配工作。
上述简单介绍了命令行多参数解析时getopt()函数的用法,若有错误,欢迎斧正与探讨;若干概念引自文献[1],若有需要相关概念更详细的解释,可前往阅读。
三. 实例
在Eureka中进行的FSI数值算例中用到如下控制选项,整理出来作为备忘。
1 | 输入 |
控制符 | 值 | 含义 | |
---|---|---|---|
./$1 | 执行程序名称,e.g. verification_oscillation_structure.gcc_v714M.st | ||
-2 | 2 | 二维 | |
-3 | 3 | 三维 | |
-L | 290 | Length | |
-H | 120 | Height | |
-W | 0 | Width | |
-J | 0.1 | critical_shear/maximum shear strain | |
-h | 8 | element size that determines the patch thickness 入口单元尺寸 | |
-D | 500 | Domain_End 计算域终点,计算域起点为0.0 | |
-r | 1.5 | searchRange, parameters for the shape function | |
-c | 1.0e-5 | cutoff, parameters for the shape function | |
-x | 3.1 | extension, parameters for the shape function | |
-b | 1.6 | beta, parameters for the shape function | |
-q | 1 | integration_order q=1表示单元的中心插入1个质量点 | |
-R | 1 | nRing 邻域控制,1表示从单元本身节点开始,如果变形大,可以设置为2 | |
-M | 0.01 | mass_factor | |
-S | true | adaptive_search | |
-Q | true | adaptive_beta | |
-U | true | updateNeighbor | |
-t | 0.1 | time step ratio 0.1表示10% | |
-T | 0.1 | total_time simulation time | |
-d | 1000 | dump,number of time steps to visualize the results | |
-v | 513 | max velocity of inflow,speed | |
-f | 1.0 | parameters for the rupture of solids,epsilon_h=1 包含裂纹扩展 | |
-G | 1.0e7 | parameters for the rupture of solids | |
-k | 1.42e5 | the bulk modulus of fluid (2.1e9 Pa for water) 体积模量 | |
-p | 1.18e-6 | the density of fluid (1.0e3 kg/m^3 for water) | |
-g | 1.4 | Gruneisen parameter in the equation of state of the fluid | |
-m | 0 | nuf,poisson’s ratio of the fluid | |
-s | 1.82e-5 | the shear viscosity coefficient of fluid (1.82e-5kg/(m.s))动力粘度 | |
-i | 0.1 | artificial viscosity coefficient to stablize the simulation 经验系数 | |
-l | 10 | artificial viscosity coefficient to stablize the simulation 经验系数 | |
-I | 0.0 | artificial viscosity coefficient to stablize the simulation 经验系数 | |
-A | 0.0 | artificial viscosity coefficient to stablize the simulation 经验系数 | |
-E | 2.5e6 | E_Solid,Young’s modulus of solid 固体材料弹性模量 | |
-P | 1.0e-4 | rho_Solid,density of solid 固体材料密度 | |
-N | 0.35 | nu_Solid,Poisson’s ratio of solid 固体材料泊松比 | |
-n | 8 | number of threads 线程数 | |
-K | 10 |
四. 参考文献
[1] http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html#Using-Getopt
2016年2月1日16:18:12
于克利夫兰