1. 1. 原理
  2. 2. commander.js
  3. 3. 如何挂载到npm上
  4. 4. 设置入口文件,并在入口文件开头写上#! /usr/bin/env node
如何开发命令行工具

这是基于新哥的脚手架工具fet源码阅读的学习笔记第一篇,主要内容是如何基于node和其他的一些工具包来完成一些简单的命令行小工具。主要实践为一个批量重命名的命令行工具(巨简单的那种),大概梳理流程和思路。

原理

node中,有一个变量叫做process的全局变量,当启动一个 Node.js 进程时,我们可以通过process.argv获得传入的命令行参数。

其中:

  • argv[0]process.execPath
  • argv[1]为正在执行 JavaScript 文件的路径
  • 其余元素是任何其他命令行参数

通过解析process.argv,我们就可以执行不同的操作。

commander.js

我们可以引用commander.js,让命令行变得更加简单。
下面简单示例一个图片重命名的node实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var program = require('commander')
var fs = require('fs')
var path = './'

program
.version('0.0.1')
.description('a test cli program')

program
.command('rename <format>') // 设置指令
.option('-n, --number <number>', '设置rename数字,默认从1开始', 1) // 设置参数
.option('-a, --after', '将fomat字符固定在数字后,默认在前')
.action(function (format, opts) { // 执行操作
fs.readdir(path, function(err, files) {
files.map(function(filename) {
var extname = getExtname(filename)
if (isImage(extname)) {
var newname = getNewName(format, opts, extname)
fs.rename(filename, newname, function(err) {
console.log(filename + ' --> ' + newname)
})
}
})
})
})

program.parse(process.argv)

function isImage (extname) {
var imageTypes = ['webp', 'png', 'svg', 'gif', 'jpg', 'jpeg', 'bmp']
return imageTypes.includes(extname)
}

function getExtname (filename) {
var filenameWithoutSuffix = filename.split(/#|\?/)[0]
return (/[^./\\]*$/.exec(filenameWithoutSuffix) || [''])[0]
}

function getNewName (format, opts, extname) {
return opts.after
? (opts.number ++) + format + '.' + extname
: format + (opts.number ++) + '.' + extname
}

运行结果如图所示:

如何挂载到npm

虽然已经有这个效果,但是rename.js能做的也只是将它所在文件夹地下的文件进行重命名,但我们实际的情况是,想在某个文件夹底下执行rename xxx的命令,而不是将rename.js搬来搬去。因此,我们可以将这个命令通过npm link挂到npm上。

我们通过npm init生成package.json文件,并增加一个bin的字段来定义我们的指令开头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "cmd-test",
"version": "1.0.0",
"description": "node图片重命名命令行工具",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"mycmd": "./index.js"
},
"author": "yx1aoq1",
"license": "ISC"
}

设置入口文件,并在入口文件开头写上#! /usr/bin/env node

1
2
3
#! /usr/bin/env node

require('../rename.js');

在执行了npm link之后,就可以看到,我们的命令已经可以起作用了。