使用commander.js创建nodejs命令行工具

Commander.js: The complete solution for node.js command-line interfaces

Commander.jsTJ 写的一个帮助快速开发Nodejs命令行工具的package。TJ同时也是 Express, mocha, koa, debug 等流行package的作者,是Nodejs社区里非常知名的高产作者,有人戏言

If you are doing things with Node, you will not escape TJ

不过现在已经退出Nodejs社区,转向Go了: Farewell Node.js. 毫不夸张的说,TJ的退出是Node社区一个非常大的损失。

Commander的方便之处在于:

  • 解析命令行参数
  • 方便的定义option(包括option的描述和其回调函数)和子命令

Option

Built-in option

Commander会为程序提供给一个默认的-hoption.
以创建一个fe命令为例:

#!/usr/bin/env node

var program = require('commander');
program
  .parse(process.argv);

其中parse函数是处理定义的option和sub-command, 解析命令行参数并触发相应的回调(下文会说)。

✍ ./fe -h

  Usage: fe [options]

  Options:

    -h, --help  output usage information

可以看到默认就有个-h参数,传入后会输出fe命令的帮助信息。

Custom option

为fe命令增加一个option,展示当前的日期。

#!/usr/bin/env node

var program = require('commander');
program
  .option('-d, --date', 'display current date')
  .parse(process.argv);

var dt = new Date();
if (program.date) {
    console.log(dt.getFullYear()
        + '-'
        + (dt.getMonth() + 1)
        + '-'
        + dt.getDate()
    );
}

option() 接收四个参数

  • 第一个参数中,-d为short option,--date为对应的long option, 二者的分割符是|,。在命令行里使用时, 这两个是等价的。 区别是后者可以在程序里通过program.date 的方式取到该option的值,此处option的值为bool,也可以为字符串
  • 第二个为option描述, 会在help信息里展示出来
  • 第三个参数为回调函数
  • 第四个参数为默认值

再看help信息:

✍ ./fe -h

  Usage: fe [options]

  Options:

    -h, --help  output usage information
    -d, --date  display current time

Unknown option

当接收到未定义的option时,程序会自动抛出错误

✍ ./fe -b

  error: unknown option `-b'

Commander同时提供了api来取消这个自动报错机制, .allowUnknownOption().

#!/usr/bin/env node

var program = require('commander');
program
  .allowUnknownOption()
  .option('-d, --date', 'display current time')
  .parse(process.argv);

// omit some detail ...

Option types

Command支持以下几种类型的option:

required 和 optional

在option的第一个参数里, 除了short, long option, 还可以指定option类型, 分隔符也是|, 其中

  • <lang> required参数, 使用时后边必须跟参数值, 否则程序会报错
  • [db] optional参数, 后面可以选择是否跟参数值
var program = require('commander');
program
  .allowUnknownOption()
  .option('-d, --date', 'display current time')
  .option('-l, --language <lang>', 'which language are u good at')
  .option('-b, --database [db]', 'which database are u good at', 'MySQL')
  .parse(process.argv);

if (program.language) {
    console.log('language: U are good at `' + program.language + '`')
}
if (program.database) {
    console.log('db: U are good at `' + program.database + '`')
}

// omit some detail ...

看下效果

✍ ./fe  -l python
language: U are good at `python`
db: U are good at `MySQL`

✍ ./fe  -l

  error: option `-l, --language <lang>' argument missing

bool

选项值为布尔型, 像上面的--date, 默认是false,当使用此参数时,program.date 为true, 否则为false

bool型option有个变种,当long option定义为no-*时默认值为true, 将

var program = require('commander');
program
  .option('-d, --no-date', 'don't display current date')
  .parse(process.argv);

var dt = new Date();
if (program.date) {
    console.log(dt.getFullYear()
        + '-'
        + (dt.getMonth() + 1)
        + '-'
        + dt.getDate()
    );
}

不带-d 参数时, 参数的默认值为true

✍ ./fe
2015-1-19

Automated --help

Commander会根据配置的option,sub-command等信息,自动生成help信息。

Custom help

可以通过监听--help事件来输出额外的帮助信息,如下面给fe命令添加了一些examples

// must be before .parse() since node's emit() is immediate
program.on('--help', function () {
    console.log('  Custom Examples:')
    console.log('')
    console.log('    ✍  fe -d')
    console.log('    ✍  fe -l python')
    console.log('')
})

program.parse(process.argv);

效果如下:

✍ ./fe -h

  Usage: fe [options]

  Options:

    -h, --help             output usage information
    -d, --no-date          display current time
    -l, --language <lang>  which language are u good at
    -b, --database [db]    which database are u good at

  Custom Examples:

    ✍  fe -d
    ✍  fe -l python

未完待续

后面会介绍 sub-command, git-style sub-command等

More

At last, welcome to contribute to the Commander.

References

comments powered by Disqus