node编写命令行工具

为了脚本的可复用性,可以把平时用到的一些便捷的脚本做成命令行的方式,使用时只需要安装对应的npm包就可以了。

环境

  • 系统:macOS系统
  • 依赖:node

过程

新建js可执行文件

// index.js
#!/usr/bin/env node
console.log('hello world');

#!/usr/bin/env node:让系统自动去环境设置寻找node目录,再调用对应路径下的解释器程序,该行必不可少。

命令行直接执行:

➜ node index.js

上面执行命令前面还需指定node,#!/usr/bin/env node的优势没利用起来,利用自动找node执行程序需要修改文件权限。默认文件权限是644(-rw-r--r--),修改文件的权限为744(-rwxr--r--)。

➜ chmod 744 index.js

现在,可以直接用对应路径的文件名就可以执行了。

➜ ./index.js
hello world

这样如果文件路径很长的时候执行脚本也简洁,还是没有直接使用命令行这么方便,进一步使用npm link

  • 首先,命令行执行npm init,创建一个package.json文件。

设置bin:将bin下的命令作为全局命令安装到node_modules中,此时可以直接运行git-auto-commit命令,不需要使用node 文件名或者对应路径文件名的方式执行。

// package.json
{
  "name": "cute-git-tools"
  "bin": {
    "git-auto-commit": "./index.js"
  },
}
  • 执行npm link:本地开发npm模块时,将npm模块链接到对应的运行项目中去,方便地对模块进行调试和测试。
    • 具体用法:
      1. 项目和模块在同一个目录下,可以使用相对路径,这样它映射的是目录名称:npm link ../module
      2. 项目和模块不在同一个目录下示例
      • 先cd到模块目录,npm link,会取package-name进行映射,创建全局link
      • 然后cd到项目目录(引用模块的地方),npm link 模块名(package.json中的name包名和package.json中bin中命令都会隐射)
        cd ~/projects/node-redis    # go into the package directory
        npm link                    # creates global link
        cd ~/projects/node-bloggy   # go into some other package directory.
        npm link redis              # link-install the package
        
      1. 解除link
      • 解除项目和模块link,项目目录下,npm uninstall 模块名
      • 解除模块全局link,模块目录下,npm uninstall -g 模块名

在项目根目录下执行:npm link,可以看到本地bin下的git-auto-commit命令映射到lib/node_modules/cute-git-tools/bin/index.js中,而lib/node_modules/cute-git-tools隐射到开发目录,这样,只要开发目录修改,执行命令行时就同步执行修改过的代码了,不用手动安装新的npm包,方便本地调试。

audited 39 packages in 1.375s

5 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

/usr/local/bin/git-auto-commit -> /usr/local/lib/node_modules/cute-git-tools/bin/index.js
/usr/local/lib/node_modules/cute-git-tools -> /Users/xxx/project/git-auto-commit
  • 执行后npm link后,建立映射关系连接,就可以直接用bin下的模块名直接执行命令了。
git-auto-commit

编写命令行脚本

编写命令行脚本有几个模块可以选择使用:

process.argv

process.argv返回一个数组,数组前两位是固定的,分别是node程序的路径和脚本存放的位置,从第三位开始才是额外输入的内容。

// index.js
#!/usr/bin/env node
console.log(process.argv);

执行:

./index.js --name=hello

输出:

[
  '/usr/local/bin/node',
  '/Users/xxxx/project/git-auto-commit/index.js',
  '--name=hello'
]

yargs 模块

yargs通过解析参数和生成优雅的用户界面来构建交互式命令行工具。
安装:

npm install --save yargs

修改脚本:

#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const argv = yargs(hideBin(process.argv)).argv
console.log(hideBin(process.argv))
console.log(argv)
console.log('hello', argv.name)

执行:

./index.js --name=world A

输出:

[ '--name=world', 'A' ]
{ _: [ 'A' ], name: 'world', '$0': 'index.js' }
hello world

hideBin相当于process.argv.slice(2)yargs模块的作用就是美化得到的命令行参数,获取参数为一个对象,方便取值。argv 对象有一个下划线(_)属性,可以获取非连词线开头的参数。

child_process

脚本可以通过node下面的 child_process 模块新建子进程,从而执行 Unix 系统命令。

#!/usr/bin/env node
const name = process.argv[2];
const exec = require('child_process').exec;
const child = exec('echo hello ' + name, function(err, stdout, stderr) {
  if (err) throw err;
  console.log(stdout);
});

执行:

./index.js world

输出:

hello world

shelljs 模块

shelljs可以兼容在(Windows/Linux/macOS)系统中执行Unix shell命令。

安装:

npm install --save shelljs

shelljs 模块重新包装了Unix shell命令,使其在都可在Windows/Linux/macOS系统使用。

#!/usr/bin/env node
const name = process.argv[2];
const shell = require("shelljs");
shell.exec("echo hello " + name);

执行:

./index.js world

输出:

hello world

shell.exec返回Object类型

[String: '* feature/nodecli\n  master\n'] {
  stdout: '* feature/nodecli\n  master\n',
  stderr: '',
  code: 0,
  cat: [Function: bound ],
  exec: [Function: bound ],
  grep: [Function: bound ],
  head: [Function: bound ],
  sed: [Function: bound ],
  sort: [Function: bound ],
  tail: [Function: bound ],
  to: [Function: bound ],
  toEnd: [Function: bound ],
  uniq: [Function: bound ]
}

readline 模块

node中的readline模块提供了用于从可读流(例如 process.stdin)每次一行地读取数据的接口。

示例:可以用来读取用户输入

#!/usr/bin/env node
const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question('What do you think of Node.js? ', (answer) => {
  console.log(`Thank you for your valuable feedback: ${answer}`);
  rl.close();
});

执行:

./index.js

输出:

What do you think of Node.js? Nice
Thank you for your valuable feedback: Nice

inquirer 模块

inquirer模块跟 readline 模块有点类似,但是inquirer模块提供更加丰富的问询模式,例如,单选,多选,用户输入等,通过回调的方式处理回答的内容。

npm install --save inquirer

脚本

#!/usr/bin/env node
const inquirer = require('inquirer')
inquirer
  .prompt([{
    type: 'input',
    message: 'input a question: ',
    name: 'answer'
  }]).then((answers) => {
    console.log(answers)
  })
  .catch((error) => {
    console.log(error)
  });

chalk 模块:命令行样式美化

chalk用于美化输出的命令行颜色等样式
安装:

npm install --save chalk

示例:打印输出

#!/usr/bin/env node
const chalk = require('chalk')

console.log(chalk.blueBright('blueBright color'))
console.log(chalk.greenBright('greenBright color'))
console.log(chalk.redBright('redBright color'))
console.log(chalk.yellow('yellow color'))

输出:


image.png

更多模块

  1. ora:优雅的终端loading展示。
  2. Inquirer:一组常见的交互式命令行用户界面。
  3. commander:node.js 命令行界面的完整解决方案。

发布npm包

  1. 登录npm账号,如果没有账号,则去npm网站注册一个,或者使用npm adduser命令,提示输入账号,密码和邮箱,然后将提示创建成功,如果已有账号,则用以下命令登录。查看是否登录:npm whoami
npm login
// 如果npm login或者npm adduser时报如下错误:npm ERR! 404 Registry returned 404 for PUT on undefined
// 则更换npm源
npm set registry https://registry.npmjs.org/
// 或者更新npm至最新版本
npm install -g npm
  1. 修改npm源,发布前,如果自己之前用的是淘宝镜像源,则需要改成npm源
npm set registry https://registry.npmjs.org/
  1. 发布
npm publish

4.有需要则恢复淘宝镜像源

npm config set registry https://registry.npm.taobao.org

更多阅读

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容