本文翻译自https://github.com/tj/commander.js
Commander
node.js命令行界面的完整解决方案,受Ruby Commander启发。
安装
$ npm install commander --save
Options 解析
使用.option()方法定义commander的选项options,也可以作为选项的文档。 下面的示例将解析来自process.argv的args和options,然后将剩下的参数(未定义的参数)赋值给commander对象的args属性(program.args),program.args是一个数组。
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq-sauce', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineapple');
if (program.bbqSauce) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);
执行
node index.js -pPbc hahah
you ordered a pizza with: - peppers - pineapple - bbq - hahah cheese
短标志可以作为单个arg传递,例如-abc相当于-a -b -c。 比如“ --template-engine”之类的多词组成的选项会变成骆驼式的program.templateEngine。
请注意,以--no前缀开头的多词选项是其后选项的布尔值的反。 例如,--no-sauce将program.sauce的值设置为false。
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.option('--no-sauce', 'Remove sauce')
.parse(process.argv);
console.log('you ordered a pizza');
if (program.sauce) console.log(' with sauce');
else console.log(' without sauce');
执行结果
node index.js --no-sauce
you ordered a pizza without sauce
版本选项
调用版本会默认将-V和--version选项添加到命令中。 当存在这些选项中的任何一个时,该命令将打印版本号并退出。
#!/usr/bin/env node
var program = require('commander');
program
.version('0.0.1')
.parse(process.argv);
执行结果:
node index.js -V 0.0.1
如果希望程序响应-v选项而不是-V选项,只需使用与option方法相同的语法将自定义标志传递给version方法
program
.version('0.0.1', '-v, --version')
版本标志可以被命名为任何值,但是长选项是必需的。
Command-specific options
你可以在命令上绑定选项
#!/usr/bin/env node
var program = require('commander');
program
.command('rm <dir>')
.option('-r, --recursive', 'Remove recursively')
.action(function (dir, cmd) {
console.log('remove ' + dir + (cmd.recursive ? ' recursively' : ''))
})
program.parse(process.argv)
node index.js rm /hahah -r remove /hahah recursively
使执行命令时,将验证该命令的options,任何未知的option都将报错。 但是,如果基于action的命令如果没有定义action,则不验证options。
Coercion
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
function collect(val, memo) {
memo.push(val);
return memo;
}
function increaseVerbosity(v, total) {
return total + 1;
}
program
.version('0.1.0')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.option('-c, --collect [value]', 'A repeatable value', collect, [])
.option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' collect: %j', program.collect);
console.log(' verbosity: %j', program.verbose);
console.log(' args: %j', program.args);
执行结果
node index.js -i 1.2 -f 1.2 -r 1..2 -l a,b -o hehe -c heihei -v zeze int: 1 float: 1.2 optional: "hehe" range: 1..2 list: ["a","b"] collect: ["heihei"] verbosity: 1 args: ["zeze"]
正则表达式
program
.version('0.1.0')
.option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')
.option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i)
.parse(process.argv);
console.log(' size: %j', program.size);
console.log(' drink: %j', program.drink);
执行结果
node index.js -s hahah -d hehe size: "medium" drink: true
size 没有输入值则报错,不符合正则则为默认值,符合正则则为size
drink 没有输入则报undefined,不符合正则则为true,符合正则则为drink
Variadic arguments可变参数
命令command有且只有最后一个参数可变不固定的。 要使参数变量可变,必须将...附加到参数名称。 这是一个例子:
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.command('rmdir <dir> [otherDirs...]')
.action(function (dir, otherDirs) {
console.log('rmdir %s', dir);
if (otherDirs) {
otherDirs.forEach(function (oDir) {
console.log('rmdir %s', oDir);
});
}
});
program.parse(process.argv);
执行结果
node index.js rmdir ./hahah aaa bbb ccc rmdir ./hahah rmdir aaa rmdir bbb rmdir ccc
可变参数的值保存在数组中, 通过program.args以及传递action的参数获取。
指定参数语法 Specify the argument syntax
#!/usr/bin/env node
var program = require('commander');
program
.version('0.1.0')
.arguments('<cmd> [env]')
.action(function (cmd, env) {
cmdValue = cmd;
envValue = env;
});
program.parse(process.argv);
if (typeof cmdValue === 'undefined') {
console.error('no command given!');
process.exit(1);
}
console.log('command:', cmdValue);
console.log('environment:', envValue || "no environment given");
执行结果
node index.js cmd env command: cmd environment: env
尖角括号<>(例如<cmd>)表示必需的输入。 方括号(例如[env])表示可选输入。
Git风格的子命令
当.command()用description参数时,不应调用.action(回调)来处理子命令,否则会出错。 这是告诉commander你要为子命令使用单独的可执行文件,就像git(1)和其他流行的工具一样。
这时commander将尝试使用名称program-command搜索条目脚本目录中的可执行文件(如./examples/index),如index-install,index-search。
可以通过调用.command()传递options。 将opts.noHelp指定true将从生成的帮助输出中删除子命令。 如果未指定其他子命令,则为opts.isDefault指定true将运行子命令。
如果程序设计为全局安装,请确保可执行文件具有正确的模式,如755。
--harmony
您可以通过两种方式启用--harmony选项:
子命令脚本使用 #! /usr/bin/env node --harmony, 注意某些操作系统版本不支持此模式。
调用命令时使用--harmony选项,如node --harmony examples/index publish。 产生子命令进程时将保留--harmony选项。
默认help Automated --help
帮助信息是根据commander已知的信息自动生成的:
$ ./examples/pizza --help Usage: pizza [options] An application for pizzas ordering Options: -h, --help output usage information -V, --version output the version number -p, --peppers Add peppers -P, --pineapple Add pineapple -b, --bbq Add bbq sauce -c, --cheese <type> Add the specified type of cheese [marble] -C, --no-cheese You do not want any cheese
自定义help Custom help
您可以通过侦听“--help”来显示任意-h, - help信息。 一旦完成,Commander将自动退出,所以程序的其余部分将不会执行,例如,在使用--help时,以下可执行文件“stuff”将不会输出。
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log('')
console.log('Examples:');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
});
program.parse(process.argv);
console.log('stuff');
执行结果
node index.js -h Usage: index [options] Options: -V, --version output the version number -f, --foo enable some foo -b, --bar enable some bar -B, --baz enable some baz -h, --help output usage information Examples: $ custom-help --help $ custom-help -h
.outputHelp(cb)
输出帮助信息而不退出。 回调cb允许在显示帮助文本之前对其进行后处理。如果要在默认情况下显示帮助(例如,如果未提供command),则可以使用以下内容:
var program = require('commander');
var colors = require('colors');
program
.version('0.1.0')
.command('getstream [url]', 'get stream URL')
.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp(make_red);
}
function make_red(txt) {
return colors.red(txt); //display the help text in red on the console
}
.help(cb)
输出帮助信息并立即退出。 回调cb允许在显示帮助文本之前对其进行后处理。
自定义事件监听 Custom event listeners
可以通过监听command和option事件来执行自定义操作。
program.on('option:verbose', function () {
process.env.VERBOSE = this.verbose;
});
// error on unknown commands
program.on('command:*', function () {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
});
示例
var program = require('commander');
program
.version('0.1.0')
.option('-C, --chdir <path>', 'change the working directory')
.option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
.option('-T, --no-tests', 'ignore test hook');
program
.command('setup [env]')
.description('run setup commands for all envs')
.option("-s, --setup_mode [mode]", "Which setup mode to use")
.action(function(env, options){
var mode = options.setup_mode || "normal";
env = env || 'all';
console.log('setup for %s env(s) with %s mode', env, mode);
});
program
.command('exec <cmd>')
.alias('ex')
.description('execute the given remote cmd')
.option("-e, --exec_mode <mode>", "Which exec mode to use")
.action(function(cmd, options){
console.log('exec "%s" using %s mode', cmd, options.exec_mode);
}).on('--help', function() {
console.log('');
console.log('Examples:');
console.log('');
console.log(' $ deploy exec sequential');
console.log(' $ deploy exec async');
});
program
.command('*')
.action(function(env){
console.log('deploying "%s"', env);
});
program.parse(process.argv);
