Hello 大家好,这个是系列教程命令行工具开发的第三篇文章命令行工具开发之使用commander完成命令和选项的解析。
上文说了命令行工具开发之命令和选项解析,今天说下命令行工具开发中的使用commander完成命令和选项的解析
“前文传送门,
命令行工具开发之使用commander完成命令和选项的解析
在命令行工具中,我们经常需要处理多个命令,比如 npm install、npm run、npm test 等。这些命令都是 npm 的子命令,我们可以通过 npm 命令来执行不同的操作。
1. 准备工作
创建项目
mkdir helloworld-cli
cd helloworld-cli
npm init -y
创建入口文件
cd helloworld-cli
touch index.js
index.js 文件内容
#!/usr/bin/env node
console.log('Hello, World!')
目录结构
helloworld-cli
├── index.js
└── package.json
在 package.json 中添加可执行文件
在package.json中添加一个bin字段,用于指定可执行文件的位置,比如:
{
"name": "helloworld-cli",
"version": "1.0.0",
"description": "CLI to test command line arguments",
"main": "index.js",
"bin": {
"helloworld-cli": "index.js"
}
}
将命令行工具添加到全局
cd helloworld-cli
npm link
不知道上面这些操作是在做什么?去看看前文呗,传送门 >> 命令行工具开发之入门(一)
2. 命令和选项解析
2.1 设计我们的命令行工具
假设,我们希望我们的命令行工具包含以下命令:
help列出所有可用的命令及其命令的描述random生成一个随机数time输出当前时间hello输出 "Hello, World!"weather输出 "某些城市的天气"
这些命令都是我们命令行工具的子命令,我们可以通过 helloworld-cli <command> 的形式来执行这些命令。
在实现这些命令之前,先介绍下这篇文章的主角commander这个 npm包是做什么的:commander 是一个用于解析命令行参数的库,我们可以使用它来解析命令行参数,并根据参数来执行不同的操作。
老规矩,要用这个包,当然是要先安装commander。
cd helloworld-cli
yarn add commander
# or
npm install commander
2.2 初始化一个commander实例
#!/usr/bin/env node
const { Command } = require('commander');
// 创建一个命令行工具实例
const program = new Command();
program
// 定义 cli工具的名称和描述
.name('helloworld-cli')
// 定义 cli工具的描述
.description('CLI to test command line arguments')
// 定义 cli工具的版本
.version('0.8.0')
// 解析命令行参数
program.parse();
这时候helloworld-cli是没有任何命令的,但是可以使用 helloworld-cli --version 来查看我们的命令行工具的版本。
cd helloworld-cli
helloworld-cli --version
还可以使用 helloworld-cli --help 来查看我们的命令行工具的帮助信息。
cd helloworld-cli
helloworld-cli --help
2.3 分别实现random、time、hello、weather命令
2.3.1 实现random命令
#!/usr/bin/env node
const { Command } = require('commander');
// 创建一个命令行工具实例
const program = new Command();
program
// 定义 cli工具的名称和描述
.name('helloworld-cli')
// 定义 cli工具的描述
.description('CLI to test command line arguments')
// 定义 cli工具的版本
.version('0.8.0')
// 定义random命令
program.command('random')
// 定义命令的描述
.description('生成一个随机数')
// 定义命令的处理函数
.action(() => {
console.log(Math.floor(Math.random() * 10))
});
// 解析命令行参数
program.parse();
运行下
random命令
cd helloworld-cli
helloworld-cli random
2.3.2 实现time命令
如果单纯输出当前时间,那么time命令的实现就跟random一样简单了,但是,我们希望time命令可以接受一个参数,用于指定时间的格式,比如:
helloworld-cli time -f YYYY-MM-DD HH:mm:ss
怎么给一个命令添加选项呢?
commander 提供了 option 方法,用于给命令添加选项。
option 方法接受三个参数,第一个参数是选项的名称,第二个参数是选项的描述,第三个参数是选项的默认值。
#!/usr/bin/env node
const { Command } = require('commander');
// 引入dayjs库,用于格式化时间
const dayjs = require('dayjs');
// 创建一个命令行工具实例
const program = new Command();
program
// 定义 cli工具的名称和描述
.name('helloworld-cli')
// 定义 cli工具的描述
.description('CLI to test command line arguments')
// 定义 cli工具的版本
.version('0.8.0')
// 定义random命令
program.command('random')
// 定义命令的描述
.description('生成一个随机数')
// 定义命令的处理函数
.action(() => {
console.log(Math.floor(Math.random() * 10))
});
// 定义time命令
program.command('time')
// 定义命令的描述
.description('输出当前时间')
// 定义命令的选项 -f YYYY-MM-DD 或者 --format YYYY-MM-DD 都可以
// --format 其实就是 -f 的别名啦
.option('-f, --format <format>', '时间格式', 'YYYY-MM-DD HH:mm:ss')
.action((options) => {
// 当命令无参数时,options为 action 的函数的第一个参数
const { format } = options;
const str = dayjs().format(format);
console.log(str);
});
// 解析命令行参数
program.parse();
运行下
time命令
cd helloworld-cli
helloworld-cli time
helloworld-cli time -f YYYY-MM-DD
helloworld-cli time --format YYYY-MM-DD
2.3.3 实现hello命令
hello命令着实简单,要不我们让它接收下用户输入的姓名name, 如果输入了姓名就输出hello ${name},否则输出hello world。
helloworld-cli hello [name]
怎么给一个命令添加参数呢?
commander提供了argument方法,用于给命令添加参数。
argument 方法接受两个参数,第一个参数是参数的名称,第二个参数是参数的描述。
上代码!!!
注意哈,argument 方法必须在 action 方法之前调用。
#!/usr/bin/env node
const { Command } = require('commander');
// 引入dayjs库,用于格式化时间
const dayjs = require('dayjs');
// 创建一个命令行工具实例
const program = new Command();
program
// 定义 cli工具的名称和描述
.name('helloworld-cli')
// 定义 cli工具的描述
.description('CLI to test command line arguments')
// 定义 cli工具的版本
.version('0.8.0')
// 定义random命令
program.command('random')
// 定义命令的描述
.description('生成一个随机数')
// 定义命令的处理函数
.action(() => {
console.log(Math.floor(Math.random() * 10))
});
program.command('time')
.description('输出当前时间')
.option('-f, --format <format>', '时间格式', 'YYYY-MM-DD HH:mm:ss')
.action((options) => {
// 当命令无参数时,options为 action 的函数的第一个参数
const { format } = options;
const str = dayjs().format(format);
console.log(str);
});
program.command('hello')
.description('输出 "Hello, World!"')
.argument('[name]', '你的名字')
.action((name) => {
const greeting = name ? `Hello, ${name}!` : 'Hello, World!';
console.log(greeting);
});
// 解析命令行参数
program.parse();
运行下
hello命令
helloworld-cli hello
helloworld-cli hello zhangsan
2.3.4 实现weather命令
weather命令,用于查询指定城市的天气情况。
weather命令需要接收一个参数,一个是城市名称(city),然后可以使用-d选项来指定要查询几天内的天气。如果用户没有指定日期,则默认查询今天的天气情况。
helloworld-cli weather [city] -d [days]
const { Command } = require('commander');
// 引入dayjs库,用于格式化时间
const dayjs = require('dayjs');
// 创建一个命令行工具实例
const program = new Command();
program
// 定义 cli工具的名称和描述
.name('helloworld-cli')
// 定义 cli工具的描述
.description('CLI to test command line arguments')
// 定义 cli工具的版本
.version('0.8.0')
// 定义random命令
program.command('random')
// 定义命令的描述
.description('生成一个随机数')
// 定义命令的处理函数
.action(() => {
console.log(Math.floor(Math.random() * 10))
});
program.command('time')
.description('输出当前时间')
// .argument('[time]', '指定时间')
.option('-f, --format <format>', '时间格式', 'YYYY-MM-DD HH:mm:ss')
.action((options) => {
// 当命令无参数时,options为 action 的函数的第一个参数
const { format } = options;
const str = dayjs().format(format);
console.log(str);
});
program.command('hello')
.description('输出 "Hello, World!"')
// .argument('<name>', '你的名字') // 必填参数
.argument('[name]', '你的名字')
.action((name) => {
const greeting = name ? `Hello, ${name}!` : 'Hello, World!';
console.log(greeting);
});
program.command('weather')
.description('输出城市天气')
// 定义命令的参数 city
.argument('[city]', 'city to search')
// 定义命令的选项 days
.option('-d, --days <day>', '几天内的天气', '1')
.action((city, options) => {
console.log(city);
console.log(options);
// 获取天数选项
const { days } = options;
// 循环输出天气
for (let index = 1; index <= days; index++) {
console.log(`Day ${index}: ${city} 的天气`);
}
});
// 解析命令行参数
program.parse();
运行下
weather命令
helloworld-cli weather 上海 -d 2
等等,我们似乎漏了个东西,就是help命令,好像没有实现。其实啊,当我们一个一个添加命令时,commander已经帮我们实现了help命令。
helloworld-cli help
3. 进阶用法
3.1 默认命令
当用户在命令行中输入helloworld-cli时,会执行默认命令。默认命令可以通过isDefault选项来指定。
program.command('glowing-terms', { isDefault: true })
.description('彩虹屁命令🌈💨')
.action(() => {
// 彩虹屁数组
const caiHongPi = [
'天涯何处无芳草,你是鲜花不是草。',
'我做事十拿九稳,现在只差你一吻。',
'月亮很亮,亮也没用,没用也亮,我喜欢你,喜欢也没用,没用也喜欢',
'谁的童话书又没合好让公主跑出来了',
`你笑起来真好看,像春天的花一样`,
'为什么我脸皮那么厚还是包不住对你的喜欢,一不小心就露馅了',
'你的眼里有星星✨我的眼里都是你',
'如果你是五彩的糖,那我就当保护你小小的糖纸',
'想和你说,今天的云和你,都十分可爱',
'我真的好喜欢你啊 第一句话是假的 第二句也是。对方申请做您心尖尖上的宝贝,接受请求吗?'
]
// 生成随机数
const randomIndex = Math.floor(Math.random() * 10);
// 随机输出彩虹屁
console.log(caiHongPi[randomIndex]);
});
3.2 参数必填
program.command('hello')
program.argument('<name>', '你的名字') // 必填参数
3.3 参数可选
program.command('hello')
program.argument('[name]', '你的名字') // 必填参数
3.4 命令增加布尔选项
// vite --open
program.command('vite')
.description('启动vite开发服务器')
// 当option 无参数时,默认为boolean类型
.option('-o, --open', '是否打开浏览器')
.action((options) => {
console.log(options);
const {
open
} = options;
if (open) {
console.log('打开浏览器');
}
})
3.5 给选项增加参数
.option('-c <city>', '指定要查询的城市')
3.6 给选项增加默认值
.option('-c <city>', '指定要查询的城市', '北京')
3.7 给选项增加参数,参数可选
.option('-c [city]', '指定要查询的城市')
3.8 程序的版本号、名称、描述动态获取
const { Command } = require('commander');
const package = require('./package.json');
program
.name(package.name)
.description(package.description)
.version(package.version);
program.parse();
完整代码
#!/usr/bin/env node
const { Command } = require('commander');
const dayjs = require('dayjs');
const package = require('./package.json');
const program = new Command();
console.log(package.name, package.version);
program
.name('helloworld-cli')
.description('CLI to test command line arguments')
.version('0.8.0')
// 获取 package.json 中的版本号及名称
program
.name(package.name)
.description(package.description)
.version(package.version);
program.command('random')
.description('生成一个随机数')
.action(() => {
console.log(Math.floor(Math.random() * 10))
});
program.command('time')
.description('输出当前时间')
// .argument('[time]', '指定时间')
.option('-f, --format <format>', '时间格式', 'YYYY-MM-DD HH:mm:ss')
.action((options) => {
// 当命令无参数时,options为 action 的函数的第一个参数
const { format } = options;
const str = dayjs().format(format);
console.log(str);
console.log(options);
});
program.command('hello')
.description('输出 "Hello, World!"')
// .argument('<name>', '你的名字') // 必填参数
.argument('[name]', '你的名字')
.action((name) => {
const greeting = name ? `Hello, ${name}!` : 'Hello, World!';
console.log(greeting);
});
program.command('weather')
.description('输出城市天气')
.argument('<city>', 'city to search')
.option('--city', 'city to search')
.option('-d, --days <day>', '几天内的天气', '1')
.action((city, options) => {
console.log(city);
console.log(options);
});
program.command('glowing-terms', { isDefault: true })
.description('彩虹屁命令🌈💨')
.action(() => {
// 彩虹屁数组
const caiHongPi = [
'天涯何处无芳草,你是鲜花不是草。',
'我做事十拿九稳,现在只差你一吻。',
'月亮很亮,亮也没用,没用也亮,我喜欢你,喜欢也没用,没用也喜欢',
'谁的童话书又没合好让公主跑出来了',
`你笑起来真好看,像春天的花一样`,
'为什么我脸皮那么厚还是包不住对你的喜欢,一不小心就露馅了',
'你的眼里有星星✨我的眼里都是你',
'如果你是五彩的糖,那我就当保护你小小的糖纸',
'想和你说,今天的云和你,都十分可爱',
'我真的好喜欢你啊 第一句话是假的 第二句也是。对方申请做您心尖尖上的宝贝,接受请求吗?'
]
// 生成随机数
const randomIndex = Math.floor(Math.random() * 10);
// 随机输出彩虹屁
console.log(caiHongPi[randomIndex]);
});
program.parse();
讲完收工~
总结一下:本篇我们开发了一个helloworld-cli命令行工具,并且学习了如何用commander 来解析命令和参数的,也通过解析命令和参数给helloworld-cli工具开发了hello、random、time、weather、help命令,并且给weather命令增加了-c选项,用来指定查询的城市。
欢迎关注我的个人公众号「「小枫学幽默」」一起成长,一起分享生活!!