命令行构造工具之 Yargs 详细介绍
目录
- 简介
- 光速开始
- 总结
简介
话说 yargs 是什么呢?简单来说,就是用来解析 cli 参数的。话不多说,我们来简单了解一下。
光速开始
.argv 一切的开始,简单的不要不要的
使用这个最简单的方式就是直接调用 .argv
这个 getter,他会自动对 process.argv
进行解析。并返回解析后的对象。
1 | // argv.js |
1 | # node argv.js -v --version --name whos |
什么缩写,什么参数,统统搞定。是不是 so easy。
在默认情况下,所有的参数只有三种值,Boolean
、String
、Array<Boolean|String
。
而且 $0
代表当前脚本的名称,这个就不多讲了
参数后面可以使用空格或者 =
。例如 -d=ok —name=bill
普通参数
如果参数没有 -
开头,那么将它放入 _
,简称为普通参数
1 | # node argv.js a b c |
简写参数
如果参数只有一个 -
开头,那么后面的参数为缩写参数,缩写参数的值默认设置成 true
。
1 | # node argv.js -a -b -c |
同时,yargs
支持将缩写参数合并在一起书写。
1 | # node argv.js -abc |
效果和上面是一样的。
如果缩写参数后面跟着普通参数,那么缩写参数的值就会自动设置成普通参数的值而不再是 true
。
1 | # node argv.js -a haha -b lala -c hehe |
那么有人问了,如果我这样写会怎么样? -abc hahaha
,let’s try.
1 | # node argv.js -abc hahaha |
结果显示,其实就和
1 | # node argv.js -a -b -c hahaha |
是一样的,可以见得,代码中其实就是将 -abc
拆成了 -a -b -c
进行解析的。
全写参数
除去上面两种参数,就剩下全写参数(不要吐槽为啥叫全写参数,因为实在是不知道该叫什么名字)
全写参数和缩写参数差不多,只不过他不能合并成一个书写,其他都是一样的
1 | # node argv.js --version --laugh haha |
结果合并
作为一个好 Module ,怎么会没有考虑到下面这种奇葩情况呢?
1 | # node argv.js -a -a -a -a -a -a -a |
大家猜猜会是什么结果 :) 此处略过 10000 秒。
1 | { _: [], |
没错,yargs
将每一个参数单独处理,然后最后合并成了一个数组,是不是很有意思,也就是说你可以写出下面的东东。
1 | # node argv.js --fuck whose --fuck your --fuck daddy --fuck |
最简单的模式,也是最有趣的模式,值得去玩。
我就要你在我的身边,.demandOption(key, msg)
**
如果你需要某个参数一定存在,这怎么办呢?难道要自己手动 if
一下,那真的好蠢啊。
.demandOption
就是这么来了
1 | // demand.js |
baby
在,世界一切太平,不管他是怎么在我的身边的。
1 | # node demand.js --baby |
baby
不在,世界爆炸(exit code != 0)
1 | # node demand.js |
.demandOption(key, msg)
的 key
支持数组和字符串,分别表示单个和多个 required
的参数。而第二个参数值在没有满足条件的时候显示的文字。
啥?你嫌我太长?还是太短:).alias
俗话说的好,参数太长怎么办,变短一点喽
其实是我自己说的,可以给一个命令取一个别名,不管是变长还是变短,都很简单。
1 | // alias.js |
1 | # node alias.js -l --long --lo -s --short |
可以看到 l
lo
long
是一样的,s
short
是一样的,可长可短,自由随意。
你要我怎样我就怎样,.boolean
.array
.number
.count
.choices
有的时候,需要某些参数是固定的格式,而不是其他的方式,那么就需要这些方法来描述一个参数的类型。这些参数对于 alias
之后的参数同样也是可以的。
.array(key)
顾名思义,直接将参数的类型设置为数组,他会将后面所有的非普通参数作为当前参数的值。
1 | // array.js |
1 | # node array.js --girls Abby Aimee --stop --girls Alisa Angelia Amanda |
.boolean(key)
将参数类型设置为 Boolean
类型。如果后面的类型不是 Boolean
类型(true
、false
),那么将不会设置为当前参数的值,并且当有多个的时候,不会合并成数组。
1 | // boolean.js |
1 | # node boolean.js I --love you and --love again |
.number(key)
将参数类型设置为 Number
类型。基本规则如下:
如果没有填写值,那么默认是
undefined
如果设置的值不合法,那么是
NaN
否则是格式化为数字,使用
Number
构造方法
1 | // number.js |
1 | # node number.js --bust --waist 24 --hips zz |
.count(key)
统计一下这个参数被使用了多少次,使用 .count
之后,参数默认就变成了 Boolean
类型,但是只统计他出现的次数。经常用来作为设置 debug 的输出级别。
1 | // count.js |
1 | # node count.js -v -vv --people --people false |
.choices(key, list)
设置某个参数只能为某些值,可以和number
boolean
count
组合。
其本质是 indexOf
操作,也就是 ===
做比较操作,所以这也就是为啥 array
不能和他匹配的原因。
1 | // choices |
1 | # node choices.js --look "oh, god" |
听说你和别人有千丝万缕的关系:( .conflicts
.implies
简单一说:
.implies(我, 她)
有我先有她,有她不一定有我.confilcts(我, 他)
有我没他,有他没我
如果两个都存在在一个参数上面的时候,implies
优先级会更高。
1 | // imcon.js |
1 | # node imcon.js --me --him --her |
大家在一起吧 :) .option
.options
其实就是将上面的的所有的命令合并成一个 object,里面的 key
就是对应的函数名,而值就是参数。只不过 .options
是很多 .option
的集合。
有用但是很简单其余参数
.default
.defaults
设置默认参数值.describe
对参数的描述.usage
设置命令的提示的使用方法.help
设置帮助的指令,添加-help
,但是没有h
,需要手动添加,可以选择是否添加help
子命令.group
分组,比如可以设置启动参数为一组,停止参数为一组,只是看起来比较舒服一些,并不影响什么内容。.normalize
对参数的值用path.normalize
.version
添加版本显示参数-version
,不过不添加缩写参数.wrap
设置信息输出的最大的列宽度,比如说-help
显示帮助参数。.wrap(null)
取消列宽限制,.wrap(require('yargs').terminalWidth())
设置为当前宽度。默认是Math.min(80, windowWidth
小弟来了 (-_-) **.command**
最简单的就是想实现类似 git 的那样的带有子命令的命令行操作,那么就需要这个东西。
他有如下的参数:
.command(cmd, desc, [builder], [handler])
.command(cmd, desc, [module])
.command(module)
builder
是构造器,可以是Object|yargs => {}
,如果是对象,那么和.options
是一样的。如果是函数,参数是yargs
可以通过上面的函数添加参数。handler
是处理器,当解析完成后,传入解析的结果,此时可以对结果进行处理。module
最简单了,就是有command
命令名aliases
别名describe
描述builder
构造器handler
处理器
当匹配到一个命令的时候, yargs
会做如下处理:
把当前命令输入到当前作用域中
清空所有的非全局的配置
如果传入了
builder
,就通过其设置当前命令解析和验证参数
如何一切正常,那么运行
handle
,如果传入了的话从当前作用域中弹出
这个位置是你的,别人抢不走 [arg1] <arg2>
有的时候希望命令必须要接受一个参数,或者接受一个可选参数,那么可以对命令使用 <>
和 []
设置他的位置。<>
表示这个命令必须要有,[]
表示这个参数可选。
有如下规则:
通过
|
设置别名,例如[name|username]
,在最后的解析中,name
和username
是一样的。最后一个可选参数支持添加
…
变成可变参数,例如downloadto <from> [to…]
那么to
是一个数组,并且必须要是命令中的最后一个可选参数才能变成可变参数。
1 | // like.js |
1 | # node like.js like you |
默认命令
有的时候当没有任何命令匹配到的时候,希望有一个默认匹配的,那么可以用 *
代替普通命令的位置。
1 | // defaultCommand.js |
1 | # node defaultCommand.js --name |
方便一点 .commandDir
表示直接从文件夹中动态加载命令。详情请参考文档
从别的地方来 .config
.env
.coerce
写到这里,作者累了,所以:
.config
动态的从命令行中接受一个json
文件路径,并自动加载。 doc.env
设置环境变量的前缀,自动将这些前缀的环境变量去掉前缀,使用小驼峰和下划线方式加载。doc.coerce
获取到变量值之后转化成别的值。doc
还有很多细节的,不过我觉得文档挺详细的,我就不多说了。
总结
感觉还是不错的,接口很简单,也通俗易懂。相比 commander
是两种不同的风格。commander
上手简单,但是前置知识有一些,而 yargs
相比前置知识的要求比较少,而且更加灵活。