命令行帮助文档语法格式详解

温馨提示:点击页面下方以展开或折叠目录

摘要:了解命令行帮助文档的语法格式有助于正确使用其命令,但是命令选项参数难懂难记,因此做以记录。

文章说明
文章作者:鴻塵
参考内容:

文章链接:https://hwame.top/20210112/command-line-description.html

1.背景

在终端下查看某个命令的用法时,通常会出现一大堆的选项参数,了解掌握其语法格式就无需某度某歌了,工作效率也会upup。

本文主要翻译自DOCOPT: Command-line interface description language,并参考Linux命令行帮助文档命令语法公式格式详解和Git命令语法格式解读

2.文档翻译

2.1.命令行界面描述语言(概述)

docopt可用于为命令行应用定义接口,并且自动生成解析器。

docopt基于已使用数十年的惯例,用于描述程序接口的帮助信息(help messages)和手册页(man pages)。docopt中正式的接口描述如下例所示:
接口描述帮助信息

上图中的例子描述了可执行程序naval_fate(海军命运)的调用接口,可由命令(commands)选项(options)位置参数(positional arguments)三者的不同组合来使用:

  • 命令(commands):shipnewmove等。
  • 选项(options):-h--help--speed=<kn>等。
  • 位置参数(positional arguments):<name><x><y>等。

该示例使用方括号[]圆括号()管道符|省略号...分别描述可选必需互斥重复的元素。这些元素组成了有效的使用模式(usage patterns),每个使用模式都以程序的名称naval_fate开始。

使用模式下方为带有描述的选项列表,它们描述了一个选项是否有 短格式(例如-h)或长格式(例如-–help 、是否有一个参数(例如–speed=<kn>),以及该参数是否有默认值(例如[default: 10])。

一个docopt实现」将提取所有上述信息并生成命令行参数解析器,当使用-h-–help选项调用程序时,界面描述的文本将作为帮助消息显示。

2.2.使用模式(usage patterns)

位于关键字usage:(不分大小写)和明显空行 之间的文本将被解释为使用模式列表关键字usage:后的第一个单词将被解释为程序名称。下面是一个无需命令行参数程序的最小示例:

1
Usage: my_program

程序可以有多个使用模式,以各种元素列出来描述该使用模式:
1
2
3
4
5
6
Usage:
my_program command --option <argument>
my_program [<optional-argument>]
my_program --another-option=<with-argument>
my_program (--either-that-option | <--or-this-argument>)
my_program <repeating-argument> <repeating-argument> ...

每个元素和结构将在下文介绍,用word表示一个由「空格」「字符串[]()|」之一...分隔的序列。

①参数<argument> ARGUMENT

<开头且>结尾的单词和大写单词将被解释为位置参数(positional arguments):

1
Usage: my_program <host> <port>

②选项-o --option

以单连字符-或双连字符--开头的单词 将被分别解释为短格式选项(一个字母的「单词」)和长格式选项,除了---本身之外【特殊含义详见下文选项参数分隔符处理标准输入】。

  • 短格式选项可以堆叠,这意味着-abc-a -b -c是等价的;
  • 长格式选项可以有位于空格等号=之后的指定的参数,即--input=ARG--input ARG等价;
  • 短格式选项可以有位于可选的空格之后的指定的参数,即-f FILE-fFILE等价;

注1:--input ARG【而非--input=ARG】这种写法语义模棱两可,因为不知道ARG到底是选项参数还是位置参数。在使用模式中,只有提供了「选项描述」时才会被解释为带参数的选项,否则将会被解释为一个选项和独立的位置参数。
注2:同样会引起歧义的是-f FILE-fFILE,因为后者不知道是多个堆叠的短格式选项(-f -F -I -L -E)还是带参数的单个选项(-f为选项,FILE为对应参数)。只有提供了选项描述时,后者这种写法才会被解释为带参数的单个选项。

③命令command

所有不遵循上述①②约定(即参数<argument>和选项--option)的「单词」,都将被解释为命令或子命令。

④可选元素[optional elements]

包含在方括号[]中的元素(选项、参数、命令)被标为「可选」。元素是否包含在相同或不同的括号内并不重要,例如下面两种写法是等价的:

1
2
3
Usage: my_program [command --option <argument>]

Usage: my_program [command] [--option] [<argument>]

⑤必选元素(required elements)

如果不在方括号[]里,那么默认情况下所有元素都是必选的。但是有时候需要用圆括号()将必选元素显式地标出,例如需要对互斥元素(见下节互斥元素)分组的时候:

1
Usage: my_program (--either-this <and-that> | <or-this>)

另一种用法是,当你需要制定如果有一个元素存在,那么就需要另一个元素,则可以这样实现:
1
Usage: my_program [(<one-argument> <another-argument>)]

在这种情况下,有效的程序调用要么没有参数,要么就有两个参数。

⑥互斥元素element | another

互斥元素以管道符|进行分隔:

1
Usage: my_program go (--up | --down | --left | --right)

在各个互斥情况下,当有一个为必选时使用圆括号()对元素进行分组,当没有必选时使用方括号[]对元素进行分组:
1
Usage: my_program go [--up | --down | --left | --right]

注意:指定多个使用模式的运行恰如管道符|,这就是说以下两者写法是等价的:
1
2
3
4
Usage: my_program run [--fast]
my_program jump [--high]

Usage: my_program (run [--fast] | jump [--high])

⑦重复元素element...

使用省略号...表示左边的一个或一组参数可被重复一次或多次:

1
2
Usage: my_program open <file>...
my_program move (<from> <to>)...

可以灵活地指定必需参数的数量,例如:
1
2
3
4
5
6
7
8
9
10
11
12
# 零个或多个必选参数(3种冗余的方法):
Usage: my_program [<file>...]
my_program [<file>]...
my_program [<file> [<file> ...]]

# 一个或多个必选参数:
Usage: my_program <file>...

# 两个或多个必选参数:
Usage: my_program <file> <file>...

# 诸如此类...

⑧选项简写[options]

[options]」是一种选项的简写方式,该方式可以避免在使用模式中列出所有的选项(从带有描述的选项列表中)。例如以下两种写法是等价的:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 简写
Usage: my_program [options] <path>

--all List everything.
--long Long output.
--human-readable Display in human-readable format.

# 非简写
Usage: my_program [--all --long --human-readable] <path>

--all List everything.
--long Long output.
--human-readable Display in human-readable format.

如果有很多选项,并且它们都适用于其中一种使用模式,那么这种简写将很有用。或者,如果同时具有短格式和长格式两种版本的选项(详见选项描述部分),则可以在一个使用模式中列出其中之一:
1
2
3
4
5
Usage: my_program [-alh] <path>

-a, --all List everything.
-l, --long Long output.
-h, --human-readable Display in human-readable format.

关于如何书写「选项描述」将在下文介绍。

⑨选项参数分隔符[--]

双连字符--在不属于选项的一部分时,按照惯例通常用于分隔选项和位置参数,以便处理诸如将文件名误认为是选项的情况。为了支持该约定,只需在使用模式的位置参数前加上[--]即可:

1
Usage: my_program [options] [--] <file>...

除此之外,--只是一个普通的命令,因此可应用于任何前述操作,譬如去掉方括号[]使其成为必选。

⑩处理标准输入[-]

单连字符-在不属于选项的一部分时,按照惯例通常表示程序用于处理标准输入stdin而非文件。如果要遵循该约定,只需将[-]添加到使用模式中。-自身仅仅是一个普通命令,可赋予任何意义。

2.3.选项描述

选项描述是位于使用模式下面的一系列选项。如果使用模式不存在歧义(详见上文选项option),则可以选择指定它们。

一个选项描述允许指定:

  • 某些短格式和长格式选项为同义词;
  • 一个选项有一个参数;
  • 选项的参数提供默认值。

这些规则遵循:以不计空格的以---开头的每一行都将视为选项描述。例如:

1
2
3
4
Options:
--verbose # GOOD,以「--」开头
-o FILE # GOOD,以「-」开头
Other: --bad # BAD,不以「-」开头

若要明确指定一个选项带有一个参数,则需:

  1. 在空格或等号=后放一个描述该参数的词,如下所示。
  2. 选项参数遵循尖括号<argument>或全大写ARGUMENT的约定。
  3. 如果有必要,可以使用逗号,分隔选项。

尽管下例中的两行都是有效的,但是建议坚持使用单一风格而不要混着用:
【注:根据下文分析中的规范书写命令第4点,推荐使用全大写而非尖括号】

1
2
-o FILE --output=FILE       # 有等号、全大写、无逗号(推荐)
-i <file>, --input <file> # 无等号、尖括号、有逗号(不推荐)

用(至少)两个空格来分隔选项和它们的非正式描述【如果只用一个空格,可能会将描述的首个词当做选项的参数】:

1
2
3
4
5
--verbose MORE text.    # BAD,将被视为选项verbose有一个参数MORE,
# 故需使用两个空格
-q Quit. # GOOD,8空格
-o FILE Output file. # GOOD,3空格
--stdout Use stdout. # GOOD,2空格

如果要为带有参数的选项设置默认值,则使用[default: the-default-value]的形式将其放到选项描述中:
1
2
3
--coefficient=K  The K coefficient [default: 2.95]
--output=FILE Output file [default: test.txt]
--directory=DIR Some directory [default: ./]

2.4.其他

3.注意事项

为了和docopt文档原有结构保持一致,本文第二章文档翻译没有在对应位置添加注释,故此列出各个注意事项。

(1)关于「命令」

在本文中使用模式格式为my_program command --option <argument>,各元素依次称为程序命令选项参数;而一般Linux命令中将这里的程序也称为命令,在这种条件下my_program command --option <argument>中各元素依次称为命令子命令选项参数,例如yum install package_name -y注意:「子命令」不一定总有,例如du -h ./

由于Linux中都是称cdls等为「命令」,因此个人倾向于「命令 子命令」的说法,而非「程序 命令」。

(2)关于「参数」

docopt文档对某些名词和概念没有具体解释,容易让人误解,尤其是翻译的时候名词的形容词化

parameterargument的区别:
The term parameter is used to describe the names for values that are expected to be supplied.
The term argument is used for the values provided for each parameter.

parameter指函数定义中的形式参数(Formal Parameter)。
argument指函数调用时的实际参数(Actual Argument)。

在本文中只有实际参数(因为只需调用程序嘛),但参数又分为位置参数选项参数

  • 位置参数是指包含于尖括号<>中的单词和大写单词;
  • 选项参数是指紧跟在选项后的参数,用于指定选项的操作对象,如-o argument--option=argument中的「argument」即选项参数。

(3)关于「选项」及歧义

「选项」主要用于改变命令执行动作的类型。一般而言,短格式选项是长格式选项的缩写,也就是一个短格式选项会有对应的长格式选项。当然也有例外,比如ls命令的短格式选项-l就没有对应的长格式选项。

上文选项option一节注解中提到的歧义问题:

  • 长格式选项--input ARG中的ARG选项参数还是位置参数
  • 短格式选项-f FILE中的FILE选项参数还是位置参数
  • 短格式选项-fFILE是由-f -F -I -L -E堆叠的多个选项还是带参数FILE单个选项-f

为了避免引起上述歧义,最好规范书写命令,如下所示:

  • 1.书写带参数的短格式选项命令时,最好写成带空格的形式-f FILE
  • 2.书写带参数的长格式选项命令时,最好写成带等号的形式--input=ARG
  • 3.事实上,带空格的形式-f FILE仍然存在歧义【FILE选项参数还是位置参数】,这是不可避免的,唯有开发者在帮助文档中用-f FILE-f <FILE>分别表示选项参数和位置参数,才能使使用者更明确。
  • 4.尽管文档中参数argument<argument>ARGUMENT统称为「位置参数」,但如果将其分别表示位置参数和选项参数则可消除该歧义。

(4)关于「可选元素」

由于可选元素是否包含在相同或不同的括号内并不重要,因此my_program [command --option <argument>]中的3个元素共有8种组合而不是2种:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 错误的「所有可能性」:
my_program
my_program command --option argument

# 正确的「所有可能性」:
my_program
my_program command
my_program --option
my_program argument
my_program command --option
my_program command argument
my_program --option argument
my_program command --option argument

如果将其改写为它的等价形式my_program [command] [--option] [<argument>]则很容易理解,难的是理解两者为何等价。

(5)关于「连字符」

双连字符单连字符除去上文特殊含义外「仅仅是一个普通命令,可赋予任何意义」

文档没有对这句话进行解释,我的理解是my_program command也可以写作my_program --或者my_program -,如果该命令是可选的,那么my_program [--]岂不是又会有到底是选项参数分隔符还是命令的歧义了。

所以说,最好还是将它们限制在选项参数分隔符处理标准输入的特定含义吧。

(6)关于「约定惯例」

约定或惯例(convention)只是为了方便彼此交流和理解而形成的规定,并不是一项带强制性的标准,因此并非所有帮助信息都遵循了这些规定,所以更多时候需要结合具体情况来推断。

以下列举几个例子:
vim命令。包括「命令的简要描述」、「使用模式」和「选项描述」三个部分,如图(截图不完整)。
vim命令

图中将「选项」写作「Arguments」,需要根据该帮助信息来推断各元素的含义。
其中,紫色框中以单连字符-表示从标准输入stdin读取文本,双连字符--表示后面的参数为文件。

同理,在cat命令中单连字符-含义与此相同,如图所示(截图为cat --help的部分内容):
cat部分命令

双连字符--rm命令中还可以标识以单连字符-开头的文件,例如删除当前文件夹下名为-foo的文件,可以使用rm -- -foorm ./-foo,如图所示(截图为rm --help的部分内容):
rm部分命令

chmod命令。包括「使用模式」、「命令描述」、「选项描述」以及「补充信息」四个部分,如图所示。
chmod命令

注意chmod命令第一种使用模式中MODE[,MODE]...重复元素写法。

who命令包括「使用模式」、「命令描述」、「选项描述」以及「补充信息」四个部分,如图所示。
who命令

注意who命令使用模式中[FILE | ARG1 ARG2]FILEARG1 ARG2这对互斥元素实际上包含了两种使用模式,这在后面的「补充信息」中也有说明即:

1
2
Usage: who [option]... [FILE]
Usage: who [option]... [(ARG1 ARG2)]

同时,上文关于「选项」及歧义中指出:一般而言,短格式选项是长格式选项的缩写,也就是一个短格式选项会有对应的长格式选项。从上面的例子可以看出,一个选项可以只有短格式选项(如-m),可以只有长格式选项(如--version),也可以同时都有(如-a,--all)。


注意:尽管大多数命令都有选项描述,因此上述提到的歧义都将解释为带参数的单个选项。但是也有一些命令没有选项描述,例如ssh命令。
ssh命令

在这种情况下,诸如-b bind_address中的address将被解释为独立的位置参数【而不是-b的选项参数】。然而此处这两种理解的运行效果没有分别,因此尽管在理论上会存在歧义,但实际上开发者会避免掉歧义情况的出现。