身為一位 CLI(Command Line Interface, CLI) 控,自幹開發用的輔助工具時當然也要自幹一個屬於自己的 CLI 工具啊!不然怎麼對得起那個常駐在下方的 Terminal 呢?不過自幹工具不是本篇重點,今天是要來跟大家講講 Commander 這一個 Node 模組。
Commander 是一個專門解析啟動程式時所輸入的參數的模組。以我們最常輸入的 npm install
這個指令為例子來說明,npm
是指程式名稱,install
則是指要程式執行的動作,這個就是所謂的參數,以 C 語言來說的話大概就是 argv
這個放在 main 括號中的東西了。
本教學共分三部分:
- 初始設定
- 小試身手
- 模組介紹
初始設定
在開始進入正題前,我們先來幫我們要做的東西來做點準備工作。
首先建立一個專案資料夾,這資料夾我們就叫…s9cli好啦!建立好後,在資料夾中建立一個 js 檔案,我想我們就命名為 index.js
。
再來是初始化整個專案為 npm 可識别的專案。
1 |
npm init |
這個指令是一個互動式指令,他會詢問各項目的值,此例除了一開始的名稱定義外,我們大多數使用預設的即可,也就是一直按 Enter 案到底 XD
這個 name 等於是你 CLI 工具的程式名稱
然後安裝所需的模組,在本篇教學中我們只需要安裝 Commander 即可。
1 |
npm install commander --save |
安裝完成後,我們就把初始化好我們的專案囉。
小試身手
在這一節中,我會稍加介紹 Commander 的用法,大多數內容取自官方的 README 檔案,有興趣可以前往閱讀原文。
第一步
因為我們要讓系統知道這支程式要能在系統層面執行,所以打開你的 index.js ,我們要在他的最上面加入這行:
1 |
#!/usr/bin/env node |
然後打開 package.json
並加入
1 2 3 4 5 6 |
..., "bin": { "s9cli": "./index.js" }, "author": "Duye", ... |
搞定!
第二步
載入模組,準備開始寫程式囉!
1 |
const program = require('commander'); |
第三步
在 index.js
中輸入以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/usr/bin/env node const program = require('commander'); program .version('0.0.1') .usage('[options]') .option('-n, --name ', 'Your name.') .parse(process.argv); // program.args < 0 代表沒有任何輸入 if (program.args.length < 1) { program.outputHelp(); // 輸出說明 process.exit(); // 關閉程式 } console.log('Hello, %s.', (program.name || 'World')); |
然後在這個專案資料夾中執行
1 |
npm link |
稍微解釋一下這個指令動作幹了什麼事。
當你執行了 npm link
後,npm 會幫這個專案資料夾在 npm 放全域模組的資料夾({prefix}/lib/node_modules/
)中置入一個捷徑(symlink),同時也會將每個 bin 執行檔建立一個捷徑到 {prefix}/bin/{name}
。如此一來,我們就可以比較好開發我們的 CLI 工具,而無需真的部屬或安裝到 npm 的管理系統中。(官網參考)
好的,以上動作完成後,我們嘗試執行看看這支程式看看結果如何。
1 2 3 |
c9cli -n Duye // output // Hello, Duye. |
嘿!一個用 Commander Line 的程式完成啦!
Commander 模組介紹
這個模組在許多以 node 開發出來的 CLI 工具中蠻常見的,例如常用來管理/執行的 PM2 就是。
它提供了一些方便的 API 供程式開法者方便使用,設定上也相當直覺,大概就是把一些想要的命令字串敲一敲,然後它就會自動地去幫你分析使用者輸入的參數,並執行你所希望執行的動作。
選項頗析 Option Parsing
這個部分是我們常看到指令後方會有一些類似 -o
或 --options
的附加參數,稱為 option,可有可無,就是一個選項這樣。這部分在程式裡面我們用 .option()
來定義。下面這個範例它會去解析來自於 program.argv
內的參數值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#!/usr/bin/env node /** * Module dependencies. */ var program = require('commander'); program .version('0.0.1') .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); |
多重輸入參數 Variadic arguments
在參數後面加上 ...
可以把這個參數定義成擁有多重輸入值的參數。範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/usr/bin/env node /** * Module dependencies. */ var program = require('commander'); program .version('0.0.1') .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); |
參數定義規則 Specify the argument syntax
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#!/usr/bin/env node var program = require('commander'); program .version('0.0.1') .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"); |
角括號(如:<cmd>
)代表這個參數是必要參數,中括號(如:[env]
)代表是可選擇性輸入的參數。
自動說明文件 Automated –help
基本的介紹大致就到這裡,若需要更多細節可以到NPM網站上翻看看。