ぶるーすくりーん

ぽんこつプログラマ日記

Node.jsを使ってCommand line ツールことはじめ

Node.js使ってCommand lineツールがつくれるということを知ったのでさっそくためしてみます。

jsファイル作成

hello-nodejs-command.jsという名前でスクリプトファイルをつくってみます。

nodejs interpreterで実行させるためのおまじないとして#!/usr/bin/env nodeを先頭に記述します。

#!/usr/bin/env node
/**
* hello-nodejs-command.js
*/

実行権を追加します。

$ chmod +x ./hello-nodejs-command.js 

ためしに実行してみます。

$ ./hello-nodejs-command.js
$

何も書いていないので当然何も起こりません (ノω・)テヘ

globalにインストールする

コマンドの中身を書いてみたい気持ちをぐっと抑えて、current directoryとか意識せずにコマンドたたけるようにglobal インストールしてみます。

まず、インストール前の状態

$ which hello-git-command
$ 

何も表示されません。

インストールできるようにpackage.jsonファイルをhello-nodejs-command.jsと同じディレクトリに作成します。

{
    "name": "hello-git-command",
    "version": "0.0.1",

    "description": "A simple command-line tool for display hello git command",
    "author": "mid0111",
    "engines": {
      "node": ">=0.10"
    },
    "dependencies": {
    },
    "bin": {
      "hello-git-command": "hello-nodejs-command.js"
    }
}

binプロパティでコマンドhello-git-commandが呼ばれた時に実行するjsファイルを指定します。

$ ls
hello-nodejs-command.js  package.json
$ sudo npm install -g
/usr/local/bin/hello-git-command -> /usr/local/lib/node_modules/hello-git-command/hello-nodejs-command.js
hello-git-command@0.0.1 /usr/local/lib/node_modules/hello-git-command
~/src/hello-git-command $ which hello-git-command
/usr/local/bin/hello-git-command

これで、/usr/local/binに実行ファイルが作成されました。

なお、スクリプトの内容を変更するたびに、/usr/local/lib/node_modules/hello-git-command/hello-nodejs-command.jsに変更を反映するために、npm install -gを実行する必要があります。

コマンド引数を取得してみる

コマンド引数はproccess.argvで配列形式で取得することができます。

#!/usr/bin/env node
/**
* hello-nodejs-command.js
*/

console.log(process.argv);

引数-xxxxを指定して実行してみると、、

$ ./hello-nodejs-command.js -xxxx
[ 'node',  '/home/mid/src/hello-git-command/hello-nodejs-command.js',  '-xxxx' ]

visionmediaさんがcommand-line interfaceのための便利ライブラリを提供してくださっているので、それを使用していい感じに引数をパースしてみます。

Commander.js
The complete solution for node.js command-line interfaces, inspired by Ruby's commander.

$ npm install commander --save

上記コマンドで、dependenciescommanderライブラリが追加されます。

  "dependencies": {
    "commander": "^2.2.0"
  },

commanderを使用してパースしていきます。

#!/usr/bin/env node
/**
* hello-nodejs-command.js
*/

var program = require('commander');

program
    .version('0.0.1')
    .usage('<keywords>')
    .parse(process.argv);

if(!program.args.length) {
    program.help();
} else {
    console.log('Keywords: ' + program.args);   
}

ためしにいろいろうってみます。

$ ./hello-nodejs-command.js 

  Usage: hello-git-command <keywords>

  Options:

    -h, --help     output usage information
    -V, --version  output the version number

$ ./hello-nodejs-command.js --version
0.0.1

$ ./hello-nodejs-command.js hello
Keywords: hello

$ ./hello-nodejs-command.js hello hello2
Keywords: hello,hello2

それでは、ちょっと改造してオプション-nまたは--nameで指定された名前を使用してSay helloしてみます。

#!/usr/bin/env node
/**
* hello-nodejs-command.js
*/

var program = require('commander');

program
    .version('0.0.1')
    .option('-n, --name [Your Name]', 'Specify your name.')
    .parse(process.argv);

if(!program.name) {
    program.help();
} else {
    console.log('Hello %s', program.name);   
}

Say hello !

$ ./hello-nodejs-command.js --name mid0111
Hello mid0111

おもしろライブラリを使ってみる

他にもvisionmediaさんのライブラリでかわいいのがあったので、遊んでみます。

visionmedia / progress bars

ライブラリ追加。

$ npm install progress --save

hello-nodejs-command.jsshowProgressBar関数を追加し、console.logでHelloする前に呼び出し追加。

var ProgressBar = require('progress');

showProgressBar();
console.log('Hello %s', program.name);   

function showProgressBar() {
  var bar = new ProgressBar(':bar', { total: 10 });
  var timer = setInterval(function () {
    bar.tick();
    if (bar.complete) {
      console.log('\ncomplete\n');
      clearInterval(timer);
    }
  }, 500);
}

実行してみる。

$ ./hello-nodejs-command.js --name mid0111
Hello mid0111
=========

complete

テキストにしてしまうとわかりにくいですが、いい感じにProgress Barが進んでます。

せっかくなので、completeの文字を*に変更して、さらに現在何%かを表示してみます。

  var bar = new ProgressBar('Waiting... [ :bar ] :percent :etas', { total: 10, complete: '*' });
  • :percent:現在の進捗何%を表示
  • :etas:時間を表示
  • complete:完了した状態を表す文字を指定
$ ./hello-nodejs-command.js --name mid0111
Hello mid0111
Waiting... [ ****----- ] 50% 3.9s

いまさら気づいたけど、ProgressBarは非同期で呼び出されるのか。
なので、ProgressBarで表す処理が終わってからHelloの処理を実行したい場合は以下のようにする必要があるみたいです。

showProgressBar();

function showProgressBar() {
  var bar = new ProgressBar('Waiting... [ :bar ] :percent :etas', { total: 10, complete: '*' });
  var timer = setInterval(function () {
    bar.tick();
    if (bar.complete) {
      console.log('\ncomplete\n');
      clearInterval(timer);
      console.log('Hello %s', program.name);   
    }
  }, 200);
}

参考

Command-line utilities with Node.js