コマンドライン引数を処理する

このユースケースで作成するCLIアプリケーションの目的は、コマンドライン引数として与えられたファイルを変換することです。 このセクションではコマンドライン引数を受け取って、それをパースするところまでを行います。

processオブジェクトとコマンドライン引数

コマンドライン引数を扱う前に、まずはprocessオブジェクトについて触れておきます。 processオブジェクトはNode.js実行環境のグローバル変数のひとつです。 processオブジェクトが提供するのは、現在のNode.jsの実行プロセスについて、情報の取得と操作をするAPIです。 詳細は公式ドキュメントを参照してください。

コマンドライン引数へのアクセスを提供するのは、processオブジェクトのargvプロパティで、文字列の配列になっています。 例として、次のようにprocess-argv.jsを記述します。

console.log(process.argv);

このスクリプトを次のようなコマンドで実行します。

$ node process-argv.js one two=three four

すると、出力結果は次のようになります。

[ 
  '/usr/local/bin/node', // Node.jsの実行プロセスのパス
  '/Users/laco/nodecli/argument-parse/src/process-argv.js', // 実行したスクリプトファイルのパス
  'one', // 1番目の引数
  'two=three', // 2番目
  'four'  // 3番目
]

1番目と2番目の要素は常にnodeコマンドと実行されたスクリプトのファイルパスになります。 つまりアプリケーションがコマンドライン引数として使うのは、3番目以降の要素です。

コマンドライン引数をパースする

process.argv配列を使えばコマンドライン引数を取得できますが、取得できるのは文字列の配列です。 そのままではアプリケーションから扱いにくいため、コマンドライン引数をパースして整形する必要があります。 文字列処理を自前で行うこともできますが、このような一般的な処理は既存のライブラリを使うと簡単に書けます。 今回はcommanderというライブラリを使ってコマンドライン引数をパースします。

commanderパッケージをインストールする

commanderはnpmnpm installコマンドを使ってインストールできます。 まだnpmの実行環境を用意できていなければ、先にアプリケーション開発の準備を参照してください。

npmでパッケージをインストールする前に、まずはpacakge.jsonというファイルを作成しましょう。 package.jsonとは、アプリケーションが依存するパッケージの種類やバージョンなどの情報を記録するJSON形式のファイルです。 package.jsonファイルのひな形は、npm initコマンドで生成できます。 通常は対話式のプロンプトによって情報を設定しますが、ここではすべてデフォルト値で問題ないため、--yesオプションを付与します。 次のコマンドを実行してpacakge.jsonを作成しましょう。

$ npm init --yes

生成されたpackage.jsonファイルは次のようになっています。

{
  "name": "nodecli",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

package.jsonファイルが用意できたら、npm installコマンドを使ってcommanderパッケージをインストールします。 このコマンドの引数にはインストールするパッケージの名前とそのバージョンを@記号でつなげて指定できます。 バージョンを指定せずにインストールすれば、その時点での最新の安定版が自動的に選択されます。 次のコマンドを実行して、commanderのバージョン2.9をインストールします。1

$ npm install commander@2.9

インストールが完了すると、package.jsonファイルは次のようになっています。

{
  "name": "nodecli",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "commander": "^2.9.0"
  }
}

また、npmのバージョンが5以上であれば package-lock.jsonファイルが生成されています。 このファイルはnpmがインストールしたパッケージの、実際のバージョンを記録するためのものです。 さきほどcommanderのバージョンは2.9としましたが、実際にインストールされるのは2.9.xに一致する最新のバージョンです。 package-lock.jsonファイルには実際にインストールされたバージョンが記録されています。 これによって、ふたたびnpm installを実行したときに異なるバージョンがインストールされることを防ぎます。

commanderパッケージを使う

npm installコマンドでインストールされたパッケージは、node_modulesというディレクトリの中に配置されています。 node_modulesディレクトリに配置されたパッケージは、require関数を使ってスクリプト中に読み込みます。 require関数はNode.js環境のグローバル関数のひとつで、指定したパッケージのモジュールを読み込めます。 commanderパッケージを読み込むには、次のように記述します。

const program = require("commander");

commanderはparseメソッドを使ってコマンドライン引数をパースします。 パースした後にoptsメソッドを呼び出すと、定義したオプションと与えられた値をオブジェクトとして取り出すことができます。 次のcommander-flag.jsでは、値をもたないオプションを真偽値にパースしています。

const program = require("commander");
program.option("--foo");
program.parse(process.argv);
const options = program.opts();
console.log(options.foo);

このスクリプトを次のように実行すると、--fooオプションがパースされ、options.fooプロパティとして扱えるようになっています。

$ node commander-flag.js --foo
true

もし、次のようなエラーが表示されたときは、commanderパッケージがnode_modulesディレクトリ内にないことを示しています。 commanderパッケージのインストールに失敗しているので、パッケージのインストールからやり直してみましょう。

Error: Cannot find module 'commander'

値をもつオプションをパースする場合は、次のcommander-param.jsのように記述します。

const program = require("commander");
program.option("--foo <text>");
program.parse(process.argv);
const options = program.opts();
console.log(options.foo);

--fooオプションに値を与えて実行すれば、文字列がoptions.fooプロパティにセットされていることがわかります。

$ node commander-param.js --foo bar
bar

このように、process.argv配列を直接扱うよりも、commanderのようなライブラリを使うことで簡単にコマンドライン引数を処理できます。 次のセクションからは、こうして受け取ったコマンドライン引数を使って、CLIアプリケーションを作成していきます。

1. --saveオプションをつけてインストールしたのと同じ意味。npm 5.0.0からは--saveがデフォルトオプションとなりました。