README 文档介绍了选项的声明与使用。大多数情况下,选项的解析行为,与您和您程序用户的期望相符。本文将详述一些特殊用例和细节问题。
有些选项可以接受可变数量的参数:
program
.option('-c, --compress [percentage]') // 0 或 1 个参数
.option('--preprocess <file...>') // 至少 1 个参数
.option('--test [name...]') // 0 或多个参数
本文中使用的示例代码接受 0 或 1 个参数。但相关的讨论对接受更多参数的选项同样适用。
关于本文档中使用的术语,参见术语表。
解析选项时,有一些潜在的问题值得注意。当一个命令既有命令参数,又有选项的时候,在解析过程中有可能出现歧义。这可能会影响用户使用您的程序。 Commander 首先解析选项的参数,而用户有可能想将选项后面跟的参数作为命令,或是作为命令参数进行解析。
program
.name('cook')
.argument('[technique]')
.option('-i, --ingredient [ingredient]', 'add cheese or given ingredient')
.action((technique, options) => {
console.log(`technique: ${technique}`);
const ingredient = (options.ingredient === true) ? 'cheese' : options.ingredient;
console.log(`ingredient: ${ingredient}`);
});
program.parse();
$ cook scrambled
technique: scrambled
ingredient: undefined
$ cook -i
technique: undefined
ingredient: cheese
$ cook -i egg
technique: undefined
ingredient: egg
$ cook -i scrambled # oops
technique: undefined
ingredient: scrambled
可以通过使用--
来表示选项和选项参数部分的结束,以此来显式地解决这一冲突:
$ node cook.js -i -- scrambled
technique: scrambled
ingredient: cheese
如果不希望强制用户掌握这种使用--
的写法,您可以尝试以下几种方案。
与其让用户理解--
的用法,您也可以直接把它作为程序语法的一部分。
program.usage('[options] -- [technique]');
$ cook --help
Usage: cook [options] -- [technique]
Options:
-i, --ingredient [ingredient] add cheese or given ingredient
-h, --help display help for command
$ cook -- scrambled
technique: scrambled
ingredient: undefined
$ cook -i -- scrambled
technique: scrambled
ingredient: cheese
Commander 遵循 GNU 解析命令的惯例,允许选项出现在命令参数之前或者之后,也可以将选项和命令参数相互穿插。 因此,通过要求把选项放在最后,命令参数就不会和选项参数相混淆。
program.usage('[technique] [options]');
$ cook --help
Usage: cook [technique] [options]
Options:
-i, --ingredient [ingredient] add cheese or given ingredient
-h, --help display help for command
$ node cook.js scrambled -i
technique: scrambled
ingredient: cheese
这个方案虽然有点激进,但是可以完美避免解析中的歧义。
program
.name('cook')
.option('-t, --technique <technique>', 'cooking technique')
.option('-i, --ingredient [ingredient]', 'add cheese or given ingredient')
.action((options) => {
console.log(`technique: ${options.technique}`);
const ingredient = (options.ingredient === true) ? 'cheese' : options.ingredient;
console.log(`ingredient: ${ingredient}`);
});
$ cook -i -t scrambled
technique: scrambled
ingredient: cheese
多个 boolean 型的短选项可以合并起来写在同一个-
号后面,比如ls -al
。同时,你也可以在其中包括一个接受参数的短选项,此时,任何跟在其后的字符都将被视作这个选项的值。
这就是说,默认情况下并不可以把多个带参数的选项合并起来。
program
.name('collect')
.option("-o, --other [count]", "other serving(s)")
.option("-v, --vegan [count]", "vegan serving(s)")
.option("-l, --halal [count]", "halal serving(s)");
program.parse(process.argv);
const opts = program.opts();
if (opts.other) console.log(`other servings: ${opts.other}`);
if (opts.vegan) console.log(`vegan servings: ${opts.vegan}`);
if (opts.halal) console.log(`halal servings: ${opts.halal}`);
$ collect -o 3
other servings: 3
$ collect -o3
other servings: 3
$ collect -l -v
vegan servings: true
halal servings: true
$ collect -lv # oops
halal servings: v
如果需要使用多个既可用作 boolean,又可以接受参数的选项,只能把它们分别声明。
$ collect -a -v -l
any servings: true
vegan servings: true
halal servings: true
在 Commander v5 之前,并不支持合并短选项和值。合并的 boolean 类型选项会被展开。
因此,-avl
将被展开为-a -v -l
。
如果您需要后向兼容,或是倾向于在短选项合并的时候把它们视作 boolean 类型,可以改变此行为:
.combineFlagAndOptionalValue(true) // `-v45` 被视为 `--vegan=45`,这是默认的行为
.combineFlagAndOptionalValue(false) // `-vl` 被视为 `-v -l`