10 月 23 - 25 日,QCon 上海站即将召开,现在购票,享9折优惠 了解详情
写点什么

私人定制 CLI 工具

  • 2019-09-27
  • 本文字数:5374 字

    阅读完需:约 18 分钟

私人定制CLI工具

1 前言

本文面向有 JavaScript 开发经验且希望入门 CLI 工具制作的开发人员。文中没有太多理论知识,通过从 0 到 1 开发一个简单的 CLI 工具,分享了 CLI 工具的开发、发布流程。看完本文,你可以学会如何"私人定制"一个 CLI 工具来提升开发效率。


总之,简单,实用,有趣。

2 什么是 CLI 工具

维基百科是这样定义 CLI 的


CLI(Command-line Interface),命令行界面,指通过输入字符组成的命令行进行操作的用户界面。


常见的 CLI 工具举例


系统命令:cd、mkdir、ifconfig


脚手架工具:create-react-app、vue-cli、yeoman


预处理器:less、sass、babel


测试工具:mocha、karma、wrk


构建工具:webpack、gulp、grunt

3 为什么要自己开发 CLI 工具

举例,如果想查看本机 ip 地址,通常我会使用 ifconfig 命令,如图:



ifconfig 执行结果


执行命令后系统输出了一堆信息,从这堆信息中找到ip地址大概需要花5秒时间,这不是我想要的。我希望的结果是这样的:



ip 执行结果


输入ip命令,直接得到本机ip地址,1秒搞定,简单快捷。


理想很丰满,现实很骨感。真实的情况是:当我在终端敲下 ip 命令时,系统给我的反馈是"command not found:ip"。



ip 执行结果


很显然,系统并没有为我提供ip这个命令,所以我们需要自己来实现它。

4 开始开发 CLI 工具

4.1 第一步:确保安装了 Node.js


node 版本检测 node 版本检测

4.2 第二步:编写脚本、测试运行

创建文件夹 ip-cli,并新建 index.js


mkdir ip-cli && cd ip-clitouch index.js
复制代码


编辑 index.js,内容如下


const os = require("os")const ip = os.networkInterfaces().en0[1].addressconst options = process.argv.slice(2)if (options[0] === '-v') {    console.log('v1.0.0')} else {    console.log(`your ip is: ${ip}`)}
复制代码


执行 node index.js,结果如下



执行脚本执行脚本

4.3 声明执行环境

执行 which env



which env


将返回的结果设置到index.js脚本的第一行,并指定脚本的解释器为node。


然后,代码就变成了下面这样:


#!/usr/bin/env node
const os = require("os")const ip = os.networkInterfaces().en0[1].addressconst options = process.argv.slice(2)if (options[0] === '-v') { console.log('v1.0.0')} else { console.log(`your ip is: ${ip}`)}
复制代码


代码中的 #!被称为 Shebang,是用来告诉编译器用什么命令执行文件的。Shebang 的一些具体用法罗列如下:


1、如果脚本文件中没有 #!这一行,那么执行时会默认采用当前 Shell 去解释这个脚本(即:

$ SHELL 环境变量)。

2、如果 #!之后的解释程序是一个可执行文件,那么执行这个脚本时,它就会把文件名及其参数一起作为参数传给那个解释程序去执行。

3、如果 #!指定的解释程序没有可执行权限,则会报错“bad interpreter: Permission

denied”。如果 #!指定的解释程序不是一个可执行文件,那么指定的解释程序会被忽略,转而交给当前的 SHELL 去执行这个脚本。

4、如果 #!指定的解释程序不存在,那么会报错“bad interpreter: No such file or directory”。注意:#!之后的解释程序,需要写其绝对路径(如:#!/bin/bash),它是不会自动到 $PATH 中寻找解释器的。

5、当然,如果你使用类似于”bash test.sh”这样的命令来执行脚本,那么 #!这一行将会被忽略掉,解释器当然是用命令行中显式指定的 bash。

6、脚本文件必须拥有可执行权限。


env 可以在系统的 PATH 目录中查找脚本解释器安装目录。


添加 #!/usr/bin/env node 是告诉系统,这个脚本使用 Node.js 来执行。这样我们就可以简化命令,执行 index.js 直接得到 ip 地址,不需要显式的调用 node index.js。

4.4 分配执行权限

在我们直接执行 index.js 后,结果如下:



执行 index.js


我们并没有得到 ip 地址,查看文件发现 index.js 没有可执行权限。



查看文件


执行 chmod +x index.js 给脚本分配可执行权限,然后 index.js 就可以执行了。



增加可执行权限

4.5 设置环境变量

执行 $PATH 查看环境变量



PATH


可以看到我电脑的 PATH 变量为


/usr/local/mongodb/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:“/usr/libexec/java_home”::/platform-tools:/tools:“/usr/libexec/java_home”:“/usr/libexec/java_home”/bin:/usr/local/mongodb/bin:/Users/qianxuemin/bin/
复制代码


这里 usr 指 Unix System Resource,而不是 User, 通常/usr/bin 下面的都是系统预装的可执行程序,会随着系统升级而改变, /usr/local/bin 目录是给用户放置自己的可执行程序的地方,推荐放在这里,不会被系统升级而覆盖同名文件。如果两个目录下有相同的可执行程序,谁优先执行受到 PATH 环境变量的影响,比如我的电脑 PATH 变量中,/usr/local/bin 优先于/usr/bin。


接下来执行 ln index.js /usr/local/bin/ip,创建 index.js 的一个硬链接文件/usr/local/bin/ip,如图:



ln


然后就可以直接使用自定义的命令ip了 。



ip


如果只是自己使用,那么一个简单的CLI工具就开发完毕了,但作为一名喜欢分享的童鞋,我希望可以把这个CLI工具分享给他人。


这时候可以选择使用 npm 管理项目,与他人共享开发成果。为了演示在 npm 项目中开发 CLI 工具的流程,我们暂时先删除刚才的命令 ip



删除命令

5 使用 npm 管理项目

5.1 初始化 npm 项目

执行 npm init -y 将项目初始化为 npm 项目。



初始化


目录结构如下:


.├── index.js└── package.json
复制代码

5.2 设置 bin 字段

在 package.json 中设置 bin 字段,定义一个命令 ip 并指定该命令执行./index.js 文件。


{  "name": "ip-cli",  "version": "1.0.0",  "description": "",  "main": "index.js",  "bin": {    "ip": "./index.js"  },  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "keywords": [],  "author": "",  "license": "ISC"}
复制代码

5.3 测试 CLI 工具

执行 npm link ,在全局的 node_modules 下生成一个符号链接。



npm link


然后就可以在全局使用 package.json 中 bin 字段定义的命令 ip 了,执行 ip 命令结果如下



ip


输出了本机IP地址,测试成功。

5.4 发布 CLI 工具

执行 npm login 登录账号,登录成功后执行 npm whoami 可以看到 npm 用户名。



npm whoami


确认无误后执行 npm publish发布npm包。


发布包的时候需要确保包的名字没有被占用,如下是包名冲突的情况。



npm publish


遇到这种情况可以选择换个名字或者加 scope,如下我给包名增加 scope,将包名由 ip-cli 改为 @qianxuemin/ip-cli。


{  "name": "@qianxuemin/ip-cli",  "version": "1.0.2",  "description": "",  "main": "index.js",  "bin": {    "ip": "./index.js"  },  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "keywords": [],  "author": "",  "license": "ISC"}
复制代码


加了 scope 后,发布包的时候需要设置访问级别,我们设置为公开。



npm publish


发布成功后,其他开发人员就可以通过 npm install @qianxuemin/ip-cli -g 安装并使用了。



ip


至此,一个简单的 CLI 工具开发、发布完成。

6 注意事项

上面演示了 CLI 工具的整体开发、发布流程,没有对细节做太多说明。如下总结了在日常开发 CLI 工具中需要注意的事项与大家分享:


1、工具应当包含完整的README.md


2、工具应当包含 help 和 version 信息


3、工具应当包含运行指示,比如加载中


4、发布之前要到 https://www.npmjs.com 查找一下自己的包名有没有被占用,如果被占用需要先修改包名或加 scope


5、发布包时,可以通过在项目中添加.npmignore 或.gitignore 文件限制发布的文件内容,.npmignore 优先级高于.gitignore。或者在 package.json 中 files 字段设置发布哪些文件或目录,它的优先级高于 .npmignore 和 .gitignore。


7 开发 CLI 工具常用的库


相比原生 Node.js,使用一些开源模块能够简化 CLI 工具的开发,提高开发效率。如下是开发 CLI 工具常用的模块:


commander: 注册、解析命令行参数


Inquirer: 让命令行与用户进行交互


chalk: 给命令行字符加颜色


shelljs: 跨平台调用 shell 命令的 node 封装


Ora: 命令行提示图标


progress: 命令行进度条


blessed-contrib: 命令行可视化组件


download-git-repo:拉取 git 仓库源代码


由于文章篇幅有限,这里就不一一进行介绍了,使用时可以直接到 https://www.npmjs.com/搜索。

8 总结

本文通过一个简单的例子分享了 CLI 工具的开发、发布流程,并总结了一些开发注意事项和常用的库。旨在帮助 JavaScript 开发人员入门 CLI 工具开发。希望大家都能在掌握 CLI 工具开发流程后,发挥想象力,开发出一些实用、好玩的东西,让我们的开发变得高效、有趣。


作者介绍:


扣丁(企业代号名),目前负责贝壳新装修平台 B 端业务研发工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/I8XXSw1eMbKLjFIcp9KWdQ


2019-09-27 13:481250

评论

发布
暂无评论
发现更多内容

Neat Syntax Design of an ETL Language (Part 1)

Bright

数据开发 ETL 大数据开发 EasySQL

科创人·酷渲科技创始人华少:用双赢思维做产品、连生态,实现规模化发展

科创人

探索质量外延 - 质量安全故事

QualityFocus

质量管理 软件质量与安全

云堡垒机单机部署的优缺点讲解-行云管家

行云管家

网络安全 堡垒机 云堡垒机 堡垒机部署

Javascript API自动代码生成需求征集

百家饭隐私计算平台创业者

JavaScript OpenAPI axios

2023年广州美博会-2023年春季广州美博会

Geek_0b38bb

美博会 2023年广州美博会 春季广州美博会 3月份广州美博会

个推TechDay直播预告 | 6月22日,开启大数据降本提效的破局之道!

个推

大数据 分布式计算 分布式存储 标签

特定MPC问题包含哪些常见技术,有什么作用,什么场景需要用到?

Jessica@数牍

隐私计算 安全多方计算 特定mpc问题

个推CTO趣谈元宇宙:从概念、成因到核心技术

个推

数据智能 元宇宙

JDK8 HashMap如何实现?

源字节1号

软件开发

web前端培训如何提高React界面性能

@零度

前端开发 React

java程序员培训 | 10年后程序员的薪资会怎么样

@零度

JAVA开发

易观分析《计算机视觉市场研究,2022》研究报告正式启动

易观分析

人工智能

InfoQ 极客传媒 15 周年庆征文|跨平台应用开发进阶(二十二) :uni-app Android APP上线准备工作汇总

No Silver Bullet

前端 签名 安全检测 6月月更 InfoQ极客传媒15周年庆

基于深度学习的水冷工作站加速遥感测绘应用研发

GPU算力

Mysql数据库查询好慢,除了索引,还能因为什么?

C++后台开发

MySQL 数据库 中间件 后端开发 C++后台开发

uni-app进阶之Weex/nvue【day6】

恒山其若陋兮

6月月更

如何使用物联网低代码平台进行数据分析?

AIRIOT

物联网 低代码开发

人才一站式服务平台开发,高层次人才管理系统

a13823115807

Vue-12-条件渲染(可重复元素)

Python研究所

6月月更

转转统一权限系统的设计与实现(前端实现篇)

转转技术团队

前端开发 umijs 权限设计

帮助中心应该怎样设计?

小炮

为什么不建议你用 MongoDB 这类产品替代时序数据库?

TDengine

数据库 tdengine 时序数据库

大数据系统包含哪些组件?需要过等保吗?

行云管家

大数据 数据 过等保

多年亿级流量下的高并发经验总结,我毫无保留的写在了这本书中

冰河

并发编程 多线程 高并发 异步编程 6月月更

【LeetCode】多个数组求交集Java题解

Albert

LeetCode 6月月更

技能速成!教你10分钟内在电脑上配置运行Hive Metastore和Presto

Alluxio

presto 技能 Alluxio hive metastore 初学者

ABAP-调用WebService服务

桥下本有油菜花

abap

华为云携手鸿蒙,培养创新型开发者

华为云开发者联盟

云计算 鸿蒙 华为云

阿里云CIPU下笔惊雷,方寸间书写中国算力故事

脑极体

java就业培训 | 面试官如何判断应聘者能力的,这一篇就够了

@零度

JAVA开发

私人定制CLI工具_文化 & 方法_扣丁_InfoQ精选文章