命令行参数解析
前面写的 node 脚本都是编译完直接跑的:
而实际上用的 Node.js 命令行工具一般都支持传入参数:
那这些命令行参数在 node 代码里怎么解析呢?
来学两个包: minimist、commander。
分别来试一下:
mkdir cli-args-test
cd cli-args-test
npm init -y写下 index.js
console.log(process.argv)跑一下:
node ./index.js -x 3 -y 4 -n5 -abc --xxx=8 aaa bbb ccc可以看到, node 会分割所有的命令行参数,放到 process.argv 里。
但一般用不到前两个参数,都是取后面的来解析:
process.argv.slice(2)先用 minimist 来解析下:
安装 minimist
npm install --save minimist改下 index.js
const minimist = require("minimist")
const argv = minimist(process.argv.slice(2))
console.log(argv)跑一下:
可以看到,所有的选项都被解析成了对象的属性,而参数放在了 _ 属性的数组里。
一般把前面这种 -xx=11 叫做选项,后面的叫做参数(也叫位置参数)。
有的同学可能会疑惑,为啥 -abc 解析成 a: true、b:true、c: true 了呢?
这就涉及到命令行参数的规范了。
简单过一下:
首先,参数的位置并不固定,可以放在选项中间、选项之前。
node ./index.js bbb -x 3 ccc -y 4 aaa
node ./index.js bbb ccc -y 4 -x 3 aaa
node ./index.js -y 4 -x 3 aaa bbb ccc其次,布尔类型的短选项可以合并:
node ./index.js aaa -y -x
node ./index.js aaa -xy但长选项不会合并:
node ./index.js aaa -xy一般一个选项会提供短选项和长选项:
选项和选项值之间可以用等号也可以用空格隔开:
node ./index.js -x=1 -y 2 aaa如果有的选项你想作为参数,可以加上 --,-- 之后的所有内容都会作为参数
node ./index.js -x=1 -- -y 2 aaa大概就这些规范。
平时敲的命令都是符合这个规范的。
minimist 等命令行解析程序都是按照这个来解析的。
minimist 还支持传入一些 options
index2.js
const minimist = require("minimist")
const argv = minimist(process.argv.slice(2), {
boolean: ["x"],
string: ["y"]
})
console.log(argv)选项就有两种 string 和 boolean,可以在 boolean 和 string 选项显示声明。
声明后会按照对应的类型来解析参数:
node ./index2.js -x 1 -y可以看到,x 虽然传入的选项值是 1 但被当做 boolean 解析为了 true。
而 -y 被解析为了 string。
没声明的选项默认也会解析:
当然,你也可以指定哪些解析哪些不解析
const minimist = require("minimist")
const argv = minimist(process.argv.slice(2), {
boolean: ["x"],
string: ["y"],
unknown(arg) {
return arg === "-u"
}
})
console.log(argv)node ./index2.js -x 1 -y -z dong
node ./index2.js -x 1 -y -u dong你还可以指定默认值:
const minimist = require("minimist")
const argv = minimist(process.argv.slice(2), {
boolean: ["x"],
string: ["y"],
unknown(arg) {
return arg === "-u"
},
default: { y: 2333 }
})
console.log(argv)指定别名:
const minimist = require("minimist")
const argv = minimist(process.argv.slice(2), {
boolean: ["x"],
string: ["y"],
unknown(arg) {
return arg === "-u"
},
default: { y: 2333 },
alias: { p: "port", t: "template" }
})
console.log(argv)node ./index2.js -p 8080这就是 minimist 的全部功能了。
虽然简单,但用的非常多:
一天就有 5000 多 w 下载量
每天都是:
(我用的时候周平均下载量没出来,但是看每天下载量也一样)
每天用的 create-vite 也是用的 minimist:
但是 minimist 的功能比较简单,只是解析参数,不能打印 help 信息、不支持解析命令自动执行对应函数,一切都要自己来做。
比如 help 信息在 create-vite 里就是自己实现的打印:
也就是这个:
当然,那是因为 create-vite 比较简单,只有一个 -t 参数。
那如果参数多了呢?
比如 @nestjs/cli,它支持这些子命令:
nest @nestjs/cli -h比如 nest new、nest start、nest build
然后子命令也有一些选项:
自己实现帮助信息的打印能累死。
而且还有命令解析后的执行、子命令解析后的执行。
这时候用 minimist 来做就不合适了。
会用 commander 来做。
@nestjs/cli 就是用的 commander:
试一下:
npm install --save commanderindex3.js
const { Command } = require("commander")
const program = new Command()
program.name("string-util").description("一些字符串工具的 CLI").version("0.8.0")
program
.command("split")
.description("分割字符串为字符数组")
.argument("<string>", "分割的字符串")
.option("--first", "只展示第一个子串")
.option("-s, --separator <char>", "分割字符", ",")
.action((str, options) => {
const limit = options.first ? 1 : undefined
console.log(str.split(options.separator, limit))
})
program.parse()跑一下:
node index3.js可以看到,会自动打印生成的 help 信息。
有一个子命令 split,看下帮助信息:
node ./index3.js split -h有两个选项 --first 是只展示第一个字符、--sperator 是指定分隔符。
试一下:
node ./index3.js split a,b,c
node ./index3.js split abc -s ''
node ./index3.js split abc -s '' --first其实这是一个功能挺全面的命令行工具了。
有 help 信息、有子命令,命令和子命令都有选项。
要是用 minimist 来做,这些都要自己实现。
但是用 commander,这些都是内置的。
回过头来看下刚才的代码:
commander 是链式调用的风格,description 传入命令描述、argument 是参数、option 是选项。
如果选项有别名、选项值,都是在 option 第一个参数里声明:
尖括号代表必填、方括号代表可选。
但选项值这里一般都是用尖括号。
选项和子命令是可选的,用方括号展示:
参数值、选项值,一般都用尖括号展示:
这不仅仅是展示用,如果你没带尖括号,就不能正常解析:
当你用了尖括号,但没有传选项值的时候,就会报错:
这种都不用自己处理,比 minimist 方便多了。
所以 commander 的下载量也比 minimist 多:
每天稳定在 1.5 亿的下载量。
但这两种库都有各自的使用场景:
minimist 只解析命令行参数,不做其他的事情,如果比较简单的命令行工具,比如只有一个 --template 选项的 create-vite,就可以用 minimist。
commander 内置了 help 打印、自动执行命令对应的 action、子命令 等功能,比 minimist 完善很多,大的命令行工具可以用 commander,比如 @nestjs/cli 就是用的 commander。
当然,还有其他的命令行解析工具,比如 yargs。
但还是 commander 用的更多,也更完善。
基本上,小的命令行工具用 minimist、大的命令行工具用 commander。
这俩二选一就行。
代码上传了文档仓库
总结
这节学了命令行解析工具 minimist 和 commander。
node 会把命令行参数传入 process.argv 数组。
自己解析比较麻烦,会用一些库来解析。
minimist 能解析命令行的选项、参数,可以设置默认值等。但是功能比较简单。
commander 还能做 help 打印、子命令、自动执行命令对应的 action 等功能。
基本上,小的命令行工具用 minimist,大的命令行工具用 commander 就可以了。