介绍
npm命令行参数的解析工具
安装
npm install commander
声明program变量
- 全局program
const { program } = require('commander');
program.version('0.0.1');
- 多实例program
const { Command } = require('commander');
const program = new Command();
program.version('0.0.1');
- 通过ES6模块方式导入
// index.mjs
import { Command } from 'commander/esm.mjs';
const program = new Command();
- 在ts中使用
// index.ts
import { Command } from 'commander';
const program = new Command();
options
基本案例
- 脚本
program
.option('-d, --debug', 'output extra debugging')
.option('-s, --small', 'small pizza size')
.option('-p, --pizza-type <type>', 'flavour of pizza');
program.parse(process.argv);
const options = program.opts();
if (options.debug) console.log(options);
console.log('pizza details:');
if (options.small) console.log('- small pizza size');
if (options.pizzaType) console.log(`- ${options.pizzaType}`);
- 命令行
$ pizza-options -d
{ debug: true, small: undefined, pizzaType: undefined }
pizza details:
$ pizza-options -p
error: option '-p, --pizza-type <type>' argument missing
$ pizza-options -ds -p vegetarian
{ debug: true, small: true, pizzaType: 'vegetarian' }
pizza details:
- small pizza size
- vegetarian
$ pizza-options --pizza-type=cheese
pizza details:
- cheese
配置项默认值
- 脚本
program
.option('-c, --cheese <type>', 'add the specified type of cheese', 'blue');
program.parse();
console.log(`cheese: ${program.opts().cheese}`);
- 命令行
$ pizza-options
cheese: blue
$ pizza-options --cheese stilton
cheese: stilton
其他类型配置项
- 脚本
program
.option('--no-sauce', 'Remove sauce')
.option('--cheese <flavour>', 'cheese flavour', 'mozzarella')
.option('--no-cheese', 'plain with no cheese')
.parse();
const options = program.opts();
const sauceStr = options.sauce ? 'sauce' : 'no sauce';
const cheeseStr = (options.cheese === false) ? 'no cheese' : `${options.cheese} cheese`;
console.log(`You ordered a pizza with ${sauceStr} and ${cheeseStr}`);
- 命令行
$ pizza-options
You ordered a pizza with sauce and mozzarella cheese
$ pizza-options --sauce
error: unknown option '--sauce'
$ pizza-options --cheese=blue
You ordered a pizza with sauce and blue cheese
$ pizza-options --no-sauce --no-cheese
You ordered a pizza with no sauce and no cheese
boolean与其他类型的复合类型配置项
- 脚本
program
.option('-c, --cheese [type]', 'Add cheese with optional type');
program.parse(process.argv);
const options = program.opts();
if (options.cheese === undefined) console.log('no cheese');
else if (options.cheese === true) console.log('add cheese');
else console.log(`add cheese type ${options.cheese}`);
- 命令行
$ pizza-options
no cheese
$ pizza-options --cheese
add cheese
$ pizza-options --cheese mozzarella
add cheese type mozzarella
必填项
- 脚本
program
.requiredOption('-c, --cheese <type>', 'pizza must have cheese');
program.parse();
- 命令行
$ pizza
error: required option '-c, --cheese <type>' not specified
动态配置项
- 脚本
program
.option('-n, --number <numbers...>', 'specify numbers')
.option('-l, --letter [letters...]', 'specify letters');
program.parse();
console.log('Options: ', program.opts());
console.log('Remaining arguments: ', program.args);
- 命令行
$ collect -n 1 2 3 --letter a b c
Options: { number: [ '1', '2', '3' ], letter: [ 'a', 'b', 'c' ] }
Remaining arguments: []
$ collect --letter=A -n80 operand
Options: { number: [ '80' ], letter: [ 'A' ] }
Remaining arguments: [ 'operand' ]
$ collect --letter -n 1 -n 2 3 -- operand
Options: { number: [ '1', '2', '3' ], letter: true }
Remaining arguments: [ 'operand' ]
# 各种命令行...
版本配置项
- 脚本
program.version('0.0.1');
- 命令行
$ ./examples/pizza -V
0.0.1
- 完整脚本
program.version('0.0.1','-v, --vers','output the current version')
带有附加功能的配置项
- 脚本
program
.addOption(new Option('-s, --secret').hideHelp())
.addOption(new Option('-t, --timeout <delay>', 'timeout in seconds').default(60, 'one minute'))
.addOption(new Option('-d, --drink <size>', 'drink size').choices(['small', 'medium', 'large']));
- 命令行
$ extra --help
Usage: help [options]
Options:
-t, --timeout <delay> timeout in seconds (default: one minute)
-d, --drink <size> drink cup size (choices: "small", "medium", "large")
-h, --help display help for command
$ extra --drink huge
error: option '-d, --drink <size>' argument 'huge' is invalid. Allowed choices are small, medium, large.
自定义选项过程
- 脚本
function myParseInt(value, dummyPrevious) {
// parseInt takes a string and a radix
const parsedValue = parseInt(value, 10);
if (isNaN(parsedValue)) {
throw new commander.InvalidOptionArgumentError('Not a number.');
}
return parsedValue;
}
function increaseVerbosity(dummyValue, previous) {
return previous + 1;
}
function collect(value, previous) {
return previous.concat([value]);
}
function commaSeparatedList(value, dummyPrevious) {
return value.split(',');
}
program
.option('-f, --float <number>', 'float argument', parseFloat)
.option('-i, --integer <number>', 'integer argument', myParseInt)
.option('-v, --verbose', 'verbosity that can be increased', increaseVerbosity, 0)
.option('-c, --collect <value>', 'repeatable value', collect, [])
.option('-l, --list <items>', 'comma separated list', commaSeparatedList)
;
program.parse();
const options = program.opts();
if (options.float !== undefined) console.log(`float: ${options.float}`);
if (options.integer !== undefined) console.log(`integer: ${options.integer}`);
if (options.verbose > 0) console.log(`verbosity: ${options.verbose}`);
if (options.collect.length > 0) console.log(options.collect);
if (options.list !== undefined) console.log(options.list);
- 命令行
$ custom -f 1e2
float: 100
$ custom --integer 2
integer: 2
$ custom -v -v -v
verbose: 3
$ custom -c a -c b -c c
[ 'a', 'b', 'c' ]
$ custom --list x,y,z
[ 'x', 'y', 'z' ]
commands
基本使用
// Command implemented using action handler (description is supplied separately to `.command`)
// Returns new command for configuring.
program
.command('clone <source> [destination]')
.description('clone a repository into a newly created directory')
.action((source, destination) => {
console.log('clone command called');
});
// Command implemented using stand-alone executable file (description is second parameter to `.command`)
// Returns `this` for adding more commands.
program
.command('start <service>', 'start named service')
.command('stop [service]', 'stop named service, or all if no name supplied');
// Command prepared separately.
// Returns `this` for adding more commands.
program
.addCommand(build.makeBuildCommand());
特殊参数语法
program
.version('0.1.0')
.arguments('<username> [password]')
.description('test command', {
username: 'user to login',
password: 'password for user, if required'
})
.action((username, password) => {
console.log('username:', username);
console.log('environment:', password || 'no password given');
});
多个参数
program
.version('0.1.0')
.command('rmdir <dirs...>')
.action(function (dirs) {
dirs.forEach((dir) => {
console.log('rmdir %s', dir);
});
});
命令处理器处理器
program
.arguments('<name>')
.option('-t, --title <honorific>', 'title to use before name')
.option('-d, --debug', 'display some debugging')
.action((name, options, command) => {
if (options.debug) {
console.error('Called %s with options %o', command.name(), options);
}
const title = options.title ? `${options.title} ` : '';
console.log(`Thank-you ${title}${name}`);
});
- 异步解析
async function run() { /* code goes here */ }
async function main() {
program
.command('run')
.action(run);
await program.parseAsync(process.argv);
}
使用executableFile指定命令名称
program
.version('0.1.0')
.command('install [name]', 'install one or more packages')
.command('search [query]', 'search with optional query')
.command('update', 'update installed packages', { executableFile: 'myUpdateSubCommand' })
.command('list', 'list packages installed', { isDefault: true });
program.parse(process.argv);
automated help
基本示例
$ node ./examples/pizza --help
Usage: pizza [options]
An application for pizza ordering
Options:
-p, --peppers Add peppers
-c, --cheese <type> Add the specified type of cheese (default: "marble")
-C, --no-cheese You do not want any cheese
-h, --help display help for command
指定命令帮助
shell help
shell --help
shell help spawn
shell spawn --help
自定义帮助
- 脚本
program
.option('-f, --foo', 'enable some foo');
program.addHelpText('after', `
Example call:
$ custom-help --help`);
- 命令行
Usage: custom-help [options]
Options:
-f, --foo enable some foo
-h, --help display help for command
Example call:
$ custom-help --help
声明周期
* beforeAll
* before
* after
* afterAll
帮助形式
.help()
:显示帮助信息并立即退出..outputHelp()
:输出帮助信息而不退出..helpInformation()
:以字符串形式获取内置命令帮助信息,以便自己处理或显示.- 区别:
.helpInformation()
,仅仅是获取并不需要展示.
允许你通过参数定义第一行帮助
program
.name("my-command")
.usage("[global options] command")
定义帮助选项的命令
program
.helpOption('-e, --HELP', 'read more information');
控制是否启用子命令帮助
program.addHelpCommand(false);
program.addHelpCommand();
program.addHelpCommand('assist [command]', 'show assistance');
更多配置
.createHelp()
helpWidth
: 指定包装宽度,对单元测试很有用sortSubcommands
: 按字母顺序对子命令排序sortOptions
: 按字母顺序对选项排序.formatHelp
: 格式化帮助
program.configureHelp({
sortSubcommands: true,
subcommandTerm: (cmd) => cmd.name() // Just show the name, instead of short usage.
});
自定义事件监听
program.on('option:verbose', function () {
process.env.VERBOSE = this.opts().verbose;
});
program.on('command:*', function (operands) {
console.error(`error: unknown command '${operands[0]}'`);
const availableCommands = program.commands.map(cmd => cmd.name());
mySuggestBestMatch(operands[0], availableCommands);
process.exitCode = 1;
});
其他
.parse() 和 .parseAsync()
- 同步异步
parsing Configuration
program -b subcommand
program subcommand -b
program --port=80 arg
program arg --port=80
Legacy options as properties
program
.storeOptionsAsProperties()
.option('-d, --debug')
.action((commandAndOptions) => {
if (commandAndOptions.debug) {
console.error(`Called ${commandAndOptions.name()}`);
}
});
在typescript中使用
node -r ts-node/register pm.ts
createCommand()
- 通过工厂函数形式创建命令
const { createCommand } = require('commander');
const program = createCommand();
#! /usr/bin/env node --harmony
- 将当前脚本链接给...
- windows不支持
退出
program.exitOverride();
try {
program.parse(process.argv);
} catch (err) {
// custom processing...
}
更改信息颜色
function errorColor(str) {
// Add ANSI escape codes to display text in red.
return `\x1b[31m${str}\x1b[0m`;
}
program
.configureOutput({
// Visibly override write routines as example!
writeOut: (str) => process.stdout.write(`[OUT] ${str}`),
writeErr: (str) => process.stdout.write(`[ERR] ${str}`),
// Highlight errors in color.
outputError: (str, write) => write(errorColor(str))
});
案例
- pizza
const { program } = require('commander');
program
.description('An application for pizza ordering')
.option('-p, --peppers', 'Add peppers')
.option('-c, --cheese <type>', 'Add the specified type of cheese', 'marble')
.option('-C, --no-cheese', 'You do not want any cheese');
program.parse();
const options = program.opts();
console.log('you ordered a pizza with:');
if (options.peppers) console.log(' - peppers');
const cheese = !options.cheese ? 'no' : options.cheese;
console.log(' - %s cheese', cheese);
- deploy
const { Command } = require('commander');
const program = new Command();
program
.version('0.0.1')
.option('-c, --config <path>', 'set config path', './deploy.conf');
program
.command('setup [env]')
.description('run setup commands for all envs')
.option('-s, --setup_mode <mode>', 'Which setup mode to use', 'normal')
.action((env, options) => {
env = env || 'all';
console.log('read config from %s', program.opts().config);
console.log('setup for %s env(s) with %s mode', env, options.setup_mode);
});
program
.command('exec <script>')
.alias('ex')
.description('execute the given remote cmd')
.option('-e, --exec_mode <mode>', 'Which exec mode to use', 'fast')
.action((script, options) => {
console.log('read config from %s', program.opts().config);
console.log('exec "%s" using %s mode and config %s', script, options.exec_mode, program.opts().config);
}).addHelpText('after', `
Examples:
$ deploy exec sequential
$ deploy exec async`
);
program.parse(process.argv);