一. 命令行格式简介
最近计划编写一个命令行解析程序,已知命令行的编写格式比较自由,例如:
ls -l -a
ls -la
ls -l –all
以上3个命令的用途是完全一致的,都是列出当前目录下所有文件的详细信息,但是写法却有很大差别,如何去解析呢。
为了做到这一点,有必要系统地去了解一下命令行的格式标准,命令行的一般格式为:
命令 [选项1] [选项2] [选项2参数] [命令参数]
下面以命令
du -h --max-depth 1 /home
为例,作出概念解释。
1. 命令
如示例中的du,命令就是程序的调用名称。
2. 选项、选项参数、命令参数
对于程序来说,命令后边的内容都是程序的“参数”,可由程序自行识别解析,并无本质不同。
但具体而言,又可以把“参数”分为3类:选项、选项参数、命令参数。
2.1. 选项
如示例中的-h、--max-depth,选项是一种特殊的程序“参数”,选项由程序提前定义,是固定的,是常量。
2.2. 选项参数
如示例中的1,它属于选项--max-depth的值,它相对固定,需要满足程序对应选项规定的范围,如必须为整数。
2.3. 命令参数
如示例中的/home,命令参数是程序的执行对象,相对自由。
二. 命令行的不同风格
为了区分命令行中的选项、选项参数、命令参数,需要制定一些规则。然而,在实践中,由于缺乏统一的规范,造就了不同的命令行风格。
1. UNIX/POSIX风格
Unix风格的命令行中,选项是以连字符“-”开头的单个字符(注意是一个字符,而不是一个单词),称之为短选项。
如果选项后面不带参数,则这样的选项被称之为模式选项。模式选项可以组合在一起使用。
例如:
mycommand -a -b
如果-a和-b是模式选项,那么就可以合并写为-ab或-ba:
mycommand -ab
mycommand -ba
如果选项带参数,这些参数要紧接在选项后面,可以以空格分开,也可以不以空格分开。
例如:
mycommand -p 9002
mycommand -p9002
mycommand -p9002可不可以理解为多个选项的合并呢?表面上来看,确实是存在歧义的,具体上来说,由于选项是固定的,则可由程序自行识别这究竟是选项合并,还是选项和选项参数的合并。
由于使用单个字符作为选项,这就限制了选项范围,如果命令非常复杂,选项可能不够用,并且难以理解。
2. GNU风格
GNU风格的命令行中,选项是以“--”开头的一个单词,称之为长选项。
例如:
mycommand --verbose。
如果选项需要带参数,则使用空格或者“=”将参数和选项分开。
例如:
mycommand --port 9501
mycommand --port=9501
GNU风格避免了UNIX风格的缺陷,尽管不是那么简洁,这也是推荐使用的命令行风格。在实践中,通常会将两种风格结合起来使用。
3. BSD风格
和UNIX/POSIX风格相比,其选项使用单个字符,且不带任何前缀。
例如:
mycommand a b c
如果是多个不带参数的选项,也可以组合在一起。
例如:
mycommand abc
如果选项需要带参数,选项参数紧跟在选项后面,可以使用空格分开,也可以不用空格。
例如:
mycommand P 9501
mycommand P9501
这种风格最简洁,但问题也最多,在不了解的情况下难以区分选项、选项参数、命令参数,我认为是垃圾。
4. X toolkit风格
原始的X toolkit风格由X toolkit进行解析,其选项选项是以“-”开头的一个单词,它首先过滤并处理某些选项(-display)然后再把过滤后的命令行传递给应用程序逻辑进行解析。
例如:
mycommand -version
如果选项需要带参数,则选项参数紧跟在这个选项后面,且使用空格分开。
例如:
mycommand -port 9501
5. DOS风格
其选项是以“/”开头的单个字符。
例如:
mycommand /C /D
选项可以合并。
例如:
mycommand /C/D
如果选项带参数,则选项参数紧跟在选项后边,不使用空格分开。
例如:
mycommand /CP/D
三. 命令行解析
命令行的解析的核心问题就是如何识别选项、选项参数、命令参数。由于命令行编写非常自由,这就给命令行的解析造成了困难。
1. 停止扫描选项和选项参数的指示符
以下面的命令行为例:
mycommand -a p1 --list 9501 test
可以认为9501是选项--list的选项参数;
也可以认为9501是命令参数,即选项--list不带参数。
这就产生了歧义。实践中,这种情况下可以使用一种称之为“扫描停止符”的标志来避免歧义。
例如:
mycommand -a p1 --list -- 9501 test
“--”是一个指示符,表明停止扫描参数,其后所有部分都是命令参数,而不是选项或选项参数。
2. 不同命令行风格之间的冲突
鉴于命令行编写格式的自由性,还有其它各种各样的命令行风格。就已知流行的几种命令行风格而言,已经出现了相互冲突的部分。
例如:
mycommand -abc
mycommand -abc
以UNIX/POSIX风格来解析,命令行带有3个参数,而以X toolkit风格来解析,则命令行只有一个参数。
因此,使用通用的规则来解析命令行是不可能实现的。