引子
本文使用Nodejs主要实现了如下形式的命令行程序
node index -A 100 //主命令
node index cmd1 -C 100 -D 200 //使用option的子命令
node index cmd2 param1 param2 param3 //使用argments的子命令
node index cmd3 -E 100 -F 200 param1 param2 //同时使用argments和option的子命令
文中option的取值通过options.option名
的方式取得,option名
在option定义时,通过--option名
定义
导入第三方package
var co = require('co');
var program = require('commander');
var colors = require('colors');
书写流程控制函数
对于每一个命令,虽然执行内容不同,但执行流程如下所示大致相同
- 使用co调用该命令的处理函数
- 执行成功后输出
success
信息,退出程序 - 执行失败后输出
error
信息,退出程序
var execute = function(target, args) {
co(function*() {
yield target.apply(this, args);
}).then(function() {
console.log(colors.green('[end]') + ' success');
process.exit();
}, function(error) {
console.log(error);
process.exit();
});
};
书写各命令的处理函数
- 主命令处理函数
接受program作为入参,从中可获取指定的option的值。
var doMain = function*(program) {
console.log(colors.green('[start]') + ' doMain1...');
// do something
console.log(program.aa);
console.log(colors.green('[end ]') + ' doMain1');
};
- 子命令1的处理函数
使用options作为入参,从中可获取指定的option的值。
var doCmd1 = function*(options) {
console.log(colors.green('[start]') + ' doCmd1...');
// do something
console.log(options.cc + ',' + options.dd);
console.log(colors.green('[end ]') + ' doCmd1');
};
- 子命令2的处理函数
使用命令行参数作为入参
var doCmd2 = function*(arg1, arg2, arg3) {
console.log(colors.green('[start]') + ' doCmd2...');
// do something
console.log(arg1 + ',' + arg2 + ',' + arg3);
console.log(colors.green('[end ]') + ' doCmd2');
};
- 子命令3的处理函数
使用命令行参数和options作为入参,options中可获取指定的option的值。
var doCmd3 = function*(arg1, arg2, arg3, options) {
console.log(colors.green('[start]') + ' doCmd3...');
// do something
console.log(arg1 + ',' + arg2 + ',' + arg3 + ',' + options.ee + ',' +
options.ff);
console.log(colors.green('[end ]') + ' doCmd3');
};
定义命令行参数,Option以及Action
- 主命令定义
定义程序的版本,option信息和帮助信息。
program
.version('0.0.1');
program
.description('使用node书写命令行程序的简单框架')
.option('-A, --aa <optionA>', 'XXXX数.')
.option('-B, --bb <optionB>', 'XXXX数.');
program.on('--help', function() {
console.log(' Examples:');
console.log('');
console.log(' node index cmd1 -C 100 -D 200');
console.log(' node index cmd2 param1 param2 param3');
console.log(' node index cmd3 -E 100 -F 200 param1 param2');
console.log('');
});
- 子命令定义
定义各命令的option和处理action,以及描述信息和帮助信息
program
.command('cmd1')
.description('只包含Option的子命令')
.option('-C, --cc <optionC>', 'XXXX数.')
.option('-D, --dd <optionD>', 'XXXX数.')
.action(function() {
execute(doCmd1, arguments);
});
program
.command('cmd2 <arg1> <arg2> [arg3]')
.description('只包含命令行参数的子命令')
.action(function() {
execute(doCmd2, arguments);
}).on('--help', function() {
console.log(' arg1:');
console.log('');
console.log(' arg1的含义说明');
console.log('');
});
program
.command('cmd3 <arg1> <arg2> [arg3]')
.option('-E, --ee <optionE>', 'XXXX数.')
.option('-F, --ff <optionF>', 'XXXX数.')
.description('同时包含命令行参数和Option的子命令')
.action(function() {
execute(doCmd3, arguments);
}).on('--help', function() {
console.log(' arg1:');
console.log('');
console.log(' arg1的含义说明');
console.log('');
});
命令行解析和执行
program.parse(process.argv);
主程序流程控制
- 设置主程序运行flag
var mainFlg = true;
- 运行程序时,如果未指定任何子命令或option信息,输出帮助信息,不执行主命令
if (!process.argv.slice(2).length) {
program.outputHelp(make_red);
mainFlg = false;
}
function make_red(txt) {
return colors.red(txt); //display the help text in red on the console
}
- 运行程序时,如果指定了子命令,执行子命令,不执行主命令
var cmds = [];
program.commands.map(function(cmd) {
cmds.push(cmd._name);
});
for (var arg of process.argv.slice(2)) {
if (cmds.indexOf(arg) >= 0) {
mainFlg = false;
}
}
if (mainFlg) {
execute(doMain, [program]);
}
完整的程序文件
'use strict';
var co = require('co');
var program = require('commander');
var colors = require('colors');
var execute = function(target, args) {
co(function*() {
yield target.apply(this, args);
}).then(function() {
console.log(colors.green('[end ]') + ' success');
process.exit();
}, function(error) {
console.log(error);
process.exit();
});
};
var doMain = function*(program) {
console.log(colors.green('[start]') + ' doMain1...');
// do something
console.log(program.aa);
console.log(colors.green('[end ]') + ' doMain1');
};
var doCmd1 = function*(options) {
console.log(colors.green('[start]') + ' doCmd1...');
// do something
console.log(options.cc + ',' + options.dd);
console.log(colors.green('[end ]') + ' doCmd1');
};
var doCmd2 = function*(arg1, arg2, arg3) {
console.log(colors.green('[start]') + ' doCmd2...');
// do something
console.log(arg1 + ',' + arg2 + ',' + arg3);
console.log(colors.green('[end ]') + ' doCmd2');
};
var doCmd3 = function*(arg1, arg2, arg3, options) {
console.log(colors.green('[start]') + ' doCmd3...');
// do something
console.log(arg1 + ',' + arg2 + ',' + arg3 + ',' + options.ee + ',' +
options.ff);
console.log(colors.green('[end ]') + ' doCmd3');
};
program
.version('0.0.1');
program
.description('使用node书写命令行程序的简单框架')
.option('-A, --aa <optionA>', 'XXXX数.')
.option('-B, --bb <optionB>', 'XXXX数.');
program.on('--help', function() {
console.log(' Examples:');
console.log('');
console.log(' node index cmd1 -C 100 -D 200');
console.log(' node index cmd2 param1 param2 param3');
console.log(' node index cmd3 -E 100 -F 200 param1 param2');
console.log('');
});
program
.command('cmd1')
.description('只包含Option的子命令')
.option('-C, --cc <optionC>', 'XXXX数.')
.option('-D, --dd <optionD>', 'XXXX数.')
.action(function() {
execute(doCmd1, arguments);
});
program
.command('cmd2 <arg1> <arg2> [arg3]')
.description('只包含命令行参数的子命令')
.action(function() {
execute(doCmd2, arguments);
}).on('--help', function() {
console.log(' arg1:');
console.log('');
console.log(' arg1的含义说明');
console.log('');
});
program
.command('cmd3 <arg1> <arg2> [arg3]')
.option('-E, --ee <optionE>', 'XXXX数.')
.option('-F, --ff <optionF>', 'XXXX数.')
.description('同时包含命令行参数和Option的子命令')
.action(function() {
execute(doCmd3, arguments);
}).on('--help', function() {
console.log(' arg1:');
console.log('');
console.log(' arg1的含义说明');
console.log('');
});
program.parse(process.argv);
var mainFlg = true;
if (!process.argv.slice(2).length) {
program.outputHelp(make_red);
mainFlg = false;
}
function make_red(txt) {
return colors.red(txt); //display the help text in red on the console
}
var cmds = [];
program.commands.map(function(cmd) {
cmds.push(cmd._name);
});
for (var arg of process.argv.slice(2)) {
if (cmds.indexOf(arg) >= 0) {
mainFlg = false;
}
}
if (mainFlg) {
execute(doMain, [program]);
}